Page 1 of 2

HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 3:07 am
by Benjamin
I just wanted to give everyone a heads up regarding HTTP status codes and an issue I encountered with Google Chrome.

It's not unusual to redirect a user after they have logged in. Reference the following code:

Code: Select all

 
function redirect($url) {
    header("Location: $url");
}
 
The above code will redirect a user to the destination with no perceived issue. An issue does occur however with google chrome, because it appears to adhere to the HTTP standards more precisely.

Using PHP's header function to send a location tag will result in an HTTP status code of 302 being sent by default, unless you have already sent a 3xx status code. So what does this mean? It means that the browser can cache the result of the request resulting in future requests immediately requesting the url sent by the previous redirection header.

So if you request login.php, get redirected to account.php, then request login.php again, login.php will not be requested. Instead, the browser will directly request account.php.

In most cases this will not make any difference. I noticed that closing the session will clear the 302 redirection cache in Google Chrome. This issue became apparent to me because I had a page that redirected to another page for logged in users when specific criteria was not being met. I noticed that they were still being redirected even after the criteria was being met. Since the destination page was not redirecting them, I realized that Google Chrome was caching the redirect.

My first attempt to resolve this issue was to change the redirection status code to "307 Temporary Redirect". This caused issues in Firefox when I submitted a form. Firefox would ask me if I wanted to resubmit the post data to the new url.

I then reviewed the status codes on w3.org and discovered that for 302 redirects the response is ONLY cacheable if indicated by the Cache-Control or Expires header.
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 final solution was to send the Cache-Control and Expires headers, along with the 302.

Code: Select all

 
function redirect($url)
{
    header("Cache-Control: max-age=0, no-cache, no-store, must-revalidate"); // HTTP/1.1
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
    header("Location: $url", true, 302);
    exit();
}
 

Re: HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 3:19 am
by Christopher
Interesting. Do you see this as how we will need to do redirects once other browsers become stricter about this -- like Chrome?

Re: HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 3:22 am
by Eran
Are we talking about the Chrome beta?

Re: HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 3:29 am
by Benjamin
arborint wrote:Interesting. Do you see this as how we will need to do redirects once other browsers become stricter about this -- like Chrome?
I believe so, but more research should be done. The default headers the server is sending are:
HTTP/1.1 200 OK
Date: Wed, 19 Aug 2009 08:24:53 GMT
Server: Apache/2.2.13 (Unix) mod_ssl/2.2.13 OpenSSL/0.9.8e-fips-rhel5 DAV/2 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
X-Powered-By: PHP/5.2.10
Transfer-Encoding: chunked
Content-Type: text/html
By default the server is not sending Cache-Control or Expires headers. So it looks like Chrome is caching the redirect because it isn't being told not to. I'll have to get back with the version, but I don't believe it's a beta.
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.
According to the standard above, the browser should not cache the result UNLESS it is told that it should. It appears Chrome is caching it for the duration of the session.

Re: HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 3:50 am
by arjan.top
"alternative" status code to 302 is 303 not 307

Re: HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 3:59 am
by Benjamin
arjan.top wrote:"alternative" status code to 302 is 303 not 307
I believe you are correct.

I was also referencing this post on php.net. I found it to be quite interesting, since I've never seen a browser cache redirect responses up until I discovered this issue with Google Chrome.

That said, if Chrome is caching 302 redirects for the duration of a session, then we would need to specify the status code when redirecting if the destination of a redirect can change during the duration of a session.

So then the code could be:

Code: Select all

 
function redirect($url) {
    header("Location: $url", true, 303);
    exit();
}
 
Just so we are all on the same page, here are the status codes: http://www.w3.org/Protocols/rfc2616/rfc ... ml#sec10.3

Re: HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 1:42 pm
by Christopher
So does the 303 work the same as the 302 code above that set headers?

Re: HEADS UP: Header Redirection http status codes

Posted: Wed Aug 19, 2009 2:45 pm
by Benjamin
According to the specs it should, but I haven't tested it yet.

Re: HEADS UP: Header Redirection http status codes

Posted: Tue Sep 01, 2009 2:39 pm
by s.dot
I see this in the newest version of firefox. I have header('Location: xxx') sprouted everywhere throughout my procedural codes :( dunno if there's a hack i can do to add in this new code easily or not.

EDIT| I wonder if setting the header for every page (such as in a global file before the page is output - and included on every page) not to cache will work the same? I don't have time to go through and change all of my header('Location....') lines.

Re: HEADS UP: Header Redirection http status codes

Posted: Tue Sep 01, 2009 3:10 pm
by Benjamin
Setting these should work:

Code: Select all

 
header("Cache-Control: max-age=0, no-cache, no-store, must-revalidate"); // HTTP/1.1
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
 

Re: HEADS UP: Header Redirection http status codes

Posted: Tue Sep 01, 2009 5:06 pm
by s.dot
astions wrote:Setting these should work:

Code: Select all

 
header("Cache-Control: max-age=0, no-cache, no-store, must-revalidate"); // HTTP/1.1
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
 
It does not work in my particular situation which is currently click a link that goes to an intermediary script (using get parameters - i know this is against the specs) and then redirects back to original script.

e.g. in admin.php i click a link that goes to _prg-admin.php?a=rejectbanner&banid=3 which updates the database accordingly and redirects back to admin.php

so this is i guess get-redirect-nothing

but in either case, i guess i'll have to try to update the header('Location: ') call.

Re: HEADS UP: Header Redirection http status codes

Posted: Tue Sep 01, 2009 5:13 pm
by Benjamin
Ok, a few things..

1. The browser knows that when it requested redirect.php it was redirected to blah.php?foo=bar. In this case, the redirect needs to send either a 303 code or the cache control code that I posted earlier. Otherwise, the browser will simply request blah.php?foo=bar again, even if the parameters are changed.

2. I'm not sure the browser should be caching it at all if it's a post request to the redirection page.

3. blah.php may be responding with a not-modified header, or the browser is caching it. In this case, you'll need to send the cache control headers on the landing page.

Re: HEADS UP: Header Redirection http status codes

Posted: Tue Sep 01, 2009 5:59 pm
by s.dot
OK, a combination of both seemed to work.. neither by themselves seemed effective.

No cache headers on the page, header location call with true, 303 in the redirect.

I'm not really up to date on these cache and header status things. If I decide to go ahead and the ",true, 303" to redirects that are done through a real post-redirect-get ... will this hurt anything?

Re: HEADS UP: Header Redirection http status codes

Posted: Tue Sep 01, 2009 6:15 pm
by Benjamin
scottayy wrote:If I decide to go ahead and the ",true, 303" to redirects that are done through a real post-redirect-get ... will this hurt anything?
I wouldn't think so offhand. My thoughts are that Firefox should not be caching a page that was sent POST data, even if it returns a redirect. So that almost sounds like a bug. You do need to be conscious of the status code that you send however, due to the differences in the way search engines handle them. You'll want to review 10.3 Redirection 3xx http status codes, as well as this post on php.net.

Re: HEADS UP: Header Redirection http status codes

Posted: Tue Sep 01, 2009 10:58 pm
by s.dot
It is indeed doing it on POST data with the p-r-g pattern. However I've looked into the problem further using the same version of firefox on another computer with the same operating system. It's not a problem on that computer. I've also just installed chrome (what the original post was about) and it is not having this problem either.

It seems it's related to the firefox install I have on my new pc (though a fresh install - or a new profile) does not fix the problem. Very weird.