

Preventing form re-submission with HTTP 303 redirects - heyjonboy
http://tumblr.jonthornton.com/post/7902581999/preventing-form-resubmission-and-http-303-redirects

======
pilif
Be really careful with this. While all browsers out there speak http 1.1 by
now and thus should support 303 redirects, many proxy servers are still living
in http 1.0 land.

A proxy shouldn't care about a status code in the 300 range, but it might
(maybe erroring out on "unknown" codes as part of some security feature).

And then there are scripts quickly thrown together using the HTTP libraries of
$LANGUAGE. You'd have to check these too if you use them in a context where
you'd also use a 303 redirect.

For what it's worth: my app is serving pages to users behind the worst
possible collections of both enterprise and personal firewalls that seem to
mangle HTTP headers at will. Heck, I even have more than 10% IE 5.5 users on
one installation.

That said, ever since 2004 I have never had one instance of a browser or proxy
resubmitting a form in response to a 302 redirect. But many instances of where
leaving the trodden path, was causing the strangest unexpected breakages due
to severely broken client software.

As such, personally, I will stay with what works and what the RFC is admitting
to generally work even if it shouldn't, instead of experimenting with
semantics for no visible gain what so ever.

Sounding bitter? Once you witness AV software altering Content-Encoding
headers without altering the encoding, you too would get bitter :-)

~~~
pornel
Proxies don't perform the redirect themselves, so they don't need to support
it, they just need to pass it through like any other 3xx.

The last UA I saw that didn't support 303 was Netscape 4.

Body of the redirect response should contain a link to the new page. This way
even time travellers form '90s will be able to reach the destination page.

------
shiflett
This post seems to be based on the belief that everything adheres to the spec.
Historically, 302 has always been interpreted like 303 is defined, and never
like 302 is defined. For example:

"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."

Does the browser you use do that?

As with cookies, developers go with what works, even if it isn't exactly what
the spec says.

History aside, it could be that there is now a difference in how 302 and 303
are interpreted by modern browsers, and I would love to see definitive tests.
Any volunteers?

~~~
heyjonboy
I've noticed older versions of Firefox trying to resubmit form data when
refreshing after a 302 redirect.

Granted there aren't many people running old versions of Firefox, but why risk
it? Even if 302 is generally interpreted like a 303, it's safer to just use a
303.

~~~
shiflett
Safer? The risk is that 303 is misinterpreted, and this risk is why we have
always used 302. I'd need evidence before taking a chance based on someone's
recollection of an older version of Firefox.

RFC 2616 mentions early misinterpretations; they are why 303 and 307 exist:

"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."

Recommending 303 sounds like a great idea, but the spec's description of 303
is what 302 is in practice, and the latest spec (2616) makes note of this
reality. Also, consistent support for 303 is not a sure bet:

"Note: Many pre-HTTP/1.1 user agents do not understand the 303 status. When
interoperability with such clients is a concern, the 302 status code may be
used instead, since most user agents react to a 302 response as described here
for 303."

Without evidence, using 303 is the riskier option.

~~~
heyjonboy
"Note: Many pre-HTTP/1.1 user agents do not understand the 303 status."

The fact is there really aren't any pre-HTTP/1.1 browsers still in use. See:
[http://serverfault.com/questions/110932/are-there-
internet-u...](http://serverfault.com/questions/110932/are-there-internet-
users-connecting-with-http-1-0)

Given that many web apps these days require javascript and CSS and HTTP/1.1 is
over 12 years old, I don't think it's realistic to worry about clients that
only support HTTP/1.0.

While 302 works in practice, it's safer to use 303, which works by definition.

~~~
dangrossman
The problem is that the browser is not the only client involved.
Corporate/country/personal proxies, firewalls and antivirus software all sit
in between some servers and clients, some of them still do not handle HTTP/1.1
correctly, and many of them will alter your headers in transit.

As your StackOverflow link mentions, Squid, a widely used proxy, is _still_
only fully implemented for HTTP/1.0.

~~~
pornel
Corporate/country/personal proxies, firewalls and antivirus software don't
perform redirects themselves, so they are irrelevant for status 303 support.

Today all clients that send HTTP/1.0 version support more than HTTP/1.0, e.g.
HTTP/1.1 Host header is basically mandatory on the web.

HTTP/1.1 compliance requires some harder things like pipelining support, and
full HTTP/1.1 caching proxy has a lot of hairy stuff to deal with (strong/weak
cache validators, stitching of partial responses, Vary support, etc.).

You can have quite decent HTTP/1.1 implementation that still doesn't deserve
to be called full HTTP/1.1.

------
beaumartinez
> _Ruby, Python, and PHP default to an HTTP 302 (Temporarily Moved) redirect._

This is very pedantic of me, but as of HTTP 1.1, HTTP 302 is _Found_ , not
_Temporarily Moved_ [1].

[1] <http://tools.ietf.org/html/rfc2616#section-10.3.3>

------
AgentConundrum
Are there any significant drawbacks to using a 303 over a 302 redirect? I ask
because I've seen this advice a number of times before - typically on
StackOverflow - and I've seen a lot of recommendations to use 302.

One question I found on a cursory search just now[1] asks whether to use 302
or 303. All three answers submitted to the question recommend 302. The key
consideration seems to be backwards compatibility with HTTP 1.0 (the 303
response was apparently added for HTTP 1.1), with the understanding that 302s
act close enough to 303s that you don't really need to worry about it. Is this
a valid concern, or is this simply an old concern that hasn't died even though
the context has changed over the years?

[1] <http://stackoverflow.com/q/5129076/1588>

~~~
pornel
I think compatibility with 1999 "new" version of HTTP is not a concern any
more.

The bigger concern I have is that it allows clients to prompt user and re-send
POST after 302 (exactly what the redirect trick is trying to prevent).

~~~
AgentConundrum
I've seen a few people say that 1.0 compatibility can be a factor with some
older proxies and similar services. I just wasn't sure how pervasive an issue
it actually was.

------
rfugger
Django had a ticket for this, and it got closed as wontfix because 302
redirects are known to work fine:

<https://code.djangoproject.com/ticket/13277>

------
Getahobby
The sample PHP code can be done with one call to the header function using the
second parameter which allows you to set the http response code. Nice article
though, learned something new today.

~~~
carbocation
Minor point of correction: the second parameter is a bool asking whether or
not to replace a previous similar header. The third parameter allows you to
set the HTTP response code.

<http://php.net/manual/en/function.header.php>

~~~
Getahobby
True. Thanks for the correction.

------
afhof
If it makes a difference, Python's urllib handles 301, 303, and 307 with the
302 handler. It also speaks 1.0

[http://hg.python.org/cpython/file/0752215f9f91/Lib/urllib.py...](http://hg.python.org/cpython/file/0752215f9f91/Lib/urllib.py#l661)

------
deweller
Great article.

This is another reminder that I should really read the HTTP/1.1 spec someday.

~~~
beaumartinez
Here's the link[1]; get at it.

[1] <http://tools.ietf.org/html/rfc2616>

------
bigiain
[meta whinge] Cursor trails? _Really?_ In 2011? Is this some sort of
GeoCities-esque retro fashion thing?

~~~
heyjonboy
Ha, hadn't thought of it that way, but I can see what you mean. I added it to
play around with Canvas, while tying in with the half-tone dot motif in the
header.

It could definitely stand to be a bit more subtle, though.

~~~
deweller
+1 for the trails. Have fun. Do what makes you happy on your own site!

------
etaty
Wikipedia has a good schema explaining this :
<http://en.wikipedia.org/wiki/Post/Redirect/Get>

------
pkteison
Can anybody confirm (or deny) that all browsers treat 303 correctly?

