top | item 2903493

IE9 deletes stuff

169 points| srozet | 14 years ago |techno-weenie.net | reply

35 comments

order
[+] patio11|14 years ago|reply
I think this is more Rails encouraging somewhat sloppy use of return values, since Rails (and the community) claim to be kind of slavish about REST-y code but in practice tend to template off of well-known Rails-y code samples rather than thinking "What am I really doing here?"

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.

[+] technoweenie|14 years ago|reply
Sure, the code is sloppy. For whatever reason, that action wasn't using "newer" rails practices to return different responses to form and ajax requests.

    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.

[+] nbpoole|14 years ago|reply
> This works great in all modern browsers, except IE9. We discovered that not only does IE9 send a real DELETE request, it also follows the redirect with another DELETE. If that redirect points to another resource, you can get a dangerous cascading effect.

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

[+] jsdalton|14 years ago|reply
Good find. I was about to post a link to that very same discussion, because the same thing crossed my mind.

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.

[+] pilif|14 years ago|reply
It's funny - about a month ago there was a discussion here that you should be using the 303 redirect in response to a post.

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 :-)

[+] EricLaw-MSFT|14 years ago|reply
Please see http://blogs.msdn.com/b/ieinternals/archive/2011/08/19/under... for a complete discussion of behavior.
[+] technoweenie|14 years ago|reply
We didn't see the issue in IE8 when we developed the feature, or this week when we tracked down the IE bug.

Something changed with IE9. Maybe jQuery detected it supports DELETE requests? I have no idea.

[+] snitko|14 years ago|reply
So I guess everything is really fine: This behavior mentioned in the last section was likely even more surprising because Internet Explorer does convert POST to GET for HTTP/301 and HTTP/302, like all other browsers
[+] ldar15|14 years ago|reply
Its funny that you can trot out the standard in your defense, cut and pasting a relavent paragraph, yet seem unable to read the immediately preceding paragraph of the spec:

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.

[+] masklinn|14 years ago|reply
You must not issue redirects to AJAX requests anyway, because Firefox will reset every single header you set on the request (custom or not), which has very annoying side effects (content negotiation will be broken post-redirect, if you're trying to use a RESTful API with content dispatching for browsers and API clients you're hosed)
[+] justincormack|14 years ago|reply
What do you mean reset every header? Not set them on the redirect? Is there a bug outstanding for this?
[+] boucher|14 years ago|reply
IE (and pretty much every browser as far as I can tell) has always supported DELETE in XMLHttpRequests (or MSXML as the case may be). Presumably Rick is talking about DELETE working in <form>s.
[+] nbpoole|14 years ago|reply
I just tried it out myself: I can't get DELETE to work in IE9 forms.

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>
[+] nirvdrum|14 years ago|reply
I don't have the time to investigate right now, but I wonder if returning a 303 rather than a 302 would yield the expected behavior. I.e., a redirect without cascading effects.
[+] guard-of-terra|14 years ago|reply
The problem here is that you can't change the standard, even you know that it states a silly thing or doesn't state an important one.

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.

[+] Sniffnoy|14 years ago|reply
As someone not too familiar with HTTP -- given that you're redirecting them to a an actual page and not some user-associated resource the page needs to grab, why would the redirected DELETE request be honored in the first place? Or am I misunderstanding what's going on here?
[+] stanleydrew|14 years ago|reply
I think what you are suggesting is that a DELETE request to a resource that should not (in the application developer's mind) be deleted should be disallowed by said developer.

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.

[+] dw0rm|14 years ago|reply
It seems that IE behavior is correct, and rails should return 303 redirect.
[+] technoweenie|14 years ago|reply
It's a vague spec, and IE behaves differently than every other browser out there. It's vague enough that they added additional redirection codes (303 and 307).
[+] tombot|14 years ago|reply
+1 for planetary references