That sounds really confusing, but it was causing me some headache on a production site today. I was redirecting a user to a given page and then trying to check which page they came from. The CGI.http_referer value kept coming up empty. But how is that possible? Clearly the user was coming from another page!
After a little bit of testing, it seems that CFLocation passes along the CGI.http_referer value of the referring page, NOT the URL of the page with the CFLocation tag on it. Take a look at this test page that I set up (cflocation_referrer.cfm). It is designed to refresh in one of two ways: an actual link or a ColdFusion CFLocation call:
<!--- Kill extra output. ---> <cfsilent> <!--- Param URL variables. ---> <cfparam name="URL.cflocation" type="string" default="No" /> <cfparam name="URL.relocate" type="boolean" default="false" /> <!--- Check to see if a CFLocaiton call has been requested. If so, we are just going to CFLocate back to self. This will allow us to see what the referrer is seen as by the target page. ---> <cfif URL.relocate> <cflocation url="#CGI.script_name#?cflocation=Yes" addtoken="false" /> </cfif> </cfsilent> <cfoutput> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>ColdFusion CFLocation And HTTP Referer</title> </head> <body> <p> CFLocation: #URL.cflocation#<br /> Referrer: #ListFirst( ListLast( CGI.http_referer, "\/" ), "?" )# </p> <p> <a href="#CGI.script_name#" >Refresh</a> | <a href="#CGI.script_name#?relocate=true" >Refresh With CFLocation</a> </p> </body> </html> </cfoutput>
Notice that if you click on the first link, the page just links right back to itself. When you do that, the rendered page gives us this output:
The other link links back to itself but flags that a CFLocation should be called to forward the user to the next page (which for testing is also the same page). The rendered page gives us this output:
Notice that CFLocation was used (YES) and a CGI.http_referer value was available. When I saw this, I was like WTF mate? So then I thought maybe the difference was that this was a development server and the other was a production server. I uploaded this file to the production server (Shhhhhh!) and ran it there. Same exact result!
I started to think I was going crazy. What was going wrong in my other code such that the referring URL was being lost. What was different? Then it occurred to me! On the production server, the page that launched the ColdFusion CFLocation tag was being accessed directly by the user. Meaning, they were manually entering the URL that then cause the CFLocation to take them to the next page:
- User enters pageA.cfm in browser location
- pageA.cfm performs CFLocation to pageB.cfm
- pageB.cfm had no CGI.http_referer value
That was a difference I could test by calling my test page manually. If you look at the code above, when I click on the link, the page refreshes and sees that is should perform a CFLocation. The page then refreshes again to take the user to the CFLocation target page. This is two refreshes. To mimic the production server scenario, all I have to do is manually enter the relocate URL. This will only cause one refresh.
So, when I enter:
... directly into the URL (thereby circumventing the first refresh), the rendered page gives us this output:
As you can see, we are sill using the CFLocation (YES), but this time we have NO referring URL value.
So what does this mean? It means that if PageA CFLocates to PageB, PageB can only see PageA's CGI.http_referer value, NOT its own CGI.http_referer value (which should be PageA). This is very strange to me. The way CFLocation works (as far as I know) is that it actually sends a header value back to the client/browser which then launches a new HTTP request to the target URL. In that case, when the browser gets the CFLocation request, it is sending the control from PageA to PageB. Wouldn't this make PageA the referrer of PageB?
Want to use code from this post? Check out the license.