ColdFusion CFLocation Only Passes Referrer Of The Referring URL

Posted May 16, 2007 at 3:36 PM by Ben Nadel

Tags: ColdFusion

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>
  •  
  • &nbsp;|&nbsp;
  •  
  • <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:

CFLocation: No
Referrer: cflocation_referrer.cfm

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:

CFLocation: Yes
Referrer: cflocation_referrer.cfm

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:

./cflocation_referrer.cfm?relocate=true

... directly into the URL (thereby circumventing the first refresh), the rendered page gives us this output:

CFLocation: Yes
Referrer:

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?



Reader Comments

May 16, 2007 at 3:43 PM // reply »
14 Comments

@Ben

Might be worth looking at a javascript solution instead (something along the lines of an onload script that performs a document.url = pageB). I believe that then you would have the expected referrer value (pageB actually came from pageA, even though the user was automatically forced there).


May 16, 2007 at 3:45 PM // reply »
14 Comments

(forgot to add this in my above response)

CFLocation does not send a full page to the browser, it only sends the header with the new location. What this means is that technically, the client might have asked for page A, but in reality they only got a header response pointing them to page B. The actual loading of Page A and then Page B only occurred on the web server. By doing the javascript method that I suggested, the client machine actually loads page A, then gets pushed to go load page B.


May 16, 2007 at 5:03 PM // reply »
172 Comments

@Ben,

Keep in mind that referrer info is controlled by the browser. Hence, it can be switched off or even even intentionally spoofed by the user. Different browsers may also behave differently.

Perhaps the reason for the behavior you are experiencing lies in how browsers interpret HTTP redirect codes (I'm not sure which one cflocation uses). E.g., code 301 ("Moved Permanently") would indicate to me that the behavior you described would actually be wanted by the server (i.e., the page moved, so you don't want the referrer to simply be the old URL).


May 16, 2007 at 5:15 PM // reply »
172 Comments

Hence, the title of this post is erroneous (ColdFusion never passes referrers). ;-)


May 16, 2007 at 5:19 PM // reply »
11,241 Comments

@Rich,

Yeah, a Javascript page would probably handle it fine, just perhaps a slightly longer drag between pages A and B. I understand that at that point (CFLocation) only headers get sent back, but in terms of client-server contact cycle, it feels like a new cycle.

@Steve,

This is a very good point. In fact, I was working with a client the other day who's firewall was stripping out all referrer in formation for each outgoing request. Basically, I agree that CGI information in general cannot be "depended" on (but I still use script_name).

Plus, I see what you are saying about the redirect and "what" the server wants you to see.

All to say, it was just something I never thought of before and I only came across it when I was trying to implement a quick fix... just goes to show you - quick fixes don't pay!


May 16, 2007 at 5:21 PM // reply »
11,241 Comments

... actually I think this is the second title this week that was dead wrong in it meaning :) The first being that XML nodes are passed by value.


May 17, 2007 at 9:09 AM // reply »
95 Comments

Ben,

have you tried using the redirect method in Java? I don't remember the exact syntax but something like getPageContext().forward("url"). Just curious if that might keep the referrer.


May 17, 2007 at 5:56 PM // reply »
11,241 Comments

@Boyan,

I don't know if it will track that way. I will have to give it a shot.


Jun 15, 2008 at 6:36 PM // reply »
1 Comments

So then, since Google appends its search info within the URL (i.e. /search?hl=en&q=coldfusion+cgi+variables). Are we able to grab this search info and place it into a session when someone gets to a site? This would be very important in tracking a user for online marketing purposes. Doing so would allow us to track whether a users completes a desired call to action on website.


May 13, 2011 at 12:36 AM // reply »
1 Comments

This article looks pretty old, but thanks Ben for posting. You saved me hours from trying to solve the same problem. I am trying to control how my pages get shared so I setup certain pages to look at the http_refer to ensure it was coming from designated pages on my site. Some of those designated pages literally were just redirects using CFLOCATION so my code would fail because the final landing page would still think someone was coming from a 3rd party site and not the page (with the CFLOCATION tag) within my own site.


Feb 9, 2013 at 2:17 AM // reply »
1 Comments

Just use the following and forget the cflocation.
cflocation has a bug too. In some cases it will not pass any session variables. Even if you use the tocken you will get none. It took me 2 hours debugging to figure it out.
As a general rule, it works as long as your browser is open. (client side) but if you open the browser via third party program or vbscript, a page that uses cflocation will kill all session variables. Use cfdump var="#session#" to check the result.
I changed it to basic Java and it works fine.
<script LANGUAGE="JavaScript">
location.href = '#YourURL#';
</script>


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 12:44 PM
Ask Ben: Query Loop Inside CFScript Tags
In cf10, if you call a function that has: local.result = {}; local.result.msg = ""; local.svc = new query(); local.svc.setSQL("SELECT * FROM..."); local.obj = local.svc.exe ... read »
May 22, 2013 at 12:29 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben: What version of Java are you using? Also, did you test users.id to see what Java reports as the data type? I wonder if it's not a Java primitive data type, but getting returned as something ... read »
May 22, 2013 at 11:47 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dana, Awesome - so it looks like this bug was fixed in ColdFusion 10. Thanks so much for double-checking that. ... read »
May 22, 2013 at 11:37 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
When I c&p and run on cf10, I get: Selected User IDs: 1,4 User 1 selected: YES - YES User 2 selected: NO - NO User 3 selected: NO - NO User 4 selected: YES - YES User 5 selected: NO - ... read »
May 22, 2013 at 11:27 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Tom, Good thought, but no dice. Both of these still exhibit the same behavior: users.id[ users.currentRow ] users[ "id" ][ users.currentRow ] It's just something whacky happening with ... read »
May 22, 2013 at 11:07 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
Could your problem be that "users.id" is actually an ARRAY, not a single value? Perhaps try it again with "users.id[1]" (I only have CF8 here at work). ... read »
May 22, 2013 at 7:52 AM
Nested Views, Routing, And Deep Linking With AngularJS
Hi, Just a quick thank you. As it happens, for my own purposes, the pending ui-router work being done in native angular is likely the one I'll adopt, but your exploration, code and documentation of ... read »
May 22, 2013 at 4:43 AM
How Do You Use The ColdFusion CFParam Tag?
'<cfparam>' or 'isDefined()and <cfset>' performs the same task.Is there any difference? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools