I have never needed to maintain a user session across multiple ColdFusion CFHttp calls before; I don't do that much screen scraping. But, I can't help people debug their own code (an unaswered "Ask Ben" question) until I understand how this works, so I thought I would give it a go. In order to do this, I created an extremely simple ColdFusion application that did nothing more than keep track of the number of times a user hit a page.
Here is the Application.cfc ColdFusion component that defines this mini application:
Launch code in new window » Download code as text file »
As you can see, this does nothing more than define the application and session management as well as the request settings. The only other page in that application, index.cfm, keeps track of the page requests for the give session:
Launch code in new window » Download code as text file »
As you can see, another really simple page; it builds the output text (the hit count string) and then streams it to the browser using ColdFusion's CFContent tag and variable attribute (the use of the Variable attribute is something I love, but it is not required).
Ok, so now, we need to set up a page outside of this application that performs a ColdFusion CFHttp call to grab that index.cfm page's output. For this demo, our test page exists in the directory above the sub application and belongs to its own application (whose definition is of no consequence for the experiment).
Since, I am not 100% sure how multiple calls using CFHttp will react, I felt the first thing I needed to try was just that - calling CFHttp multiple times without any special actions or parameters:
Launch code in new window » Download code as text file »
When I running that code, I CFDump out the two result objects returned by the vanilla CFHttp calls.
First CFHttp Request:
| | | | ||
| | ![]() | | ||
| | | |
Second CFHttp Request:
| | | | ||
| | ![]() | | ||
| | | |
Notice that in both CFHttp result objects, the FileContent variable (highlighted in yellow) reports "Hit Count: 1". This happens because the session was not maintained across the two calls and hence, each request was given a new SESSION scope and therefore a new base line hit count. Furthermore, if you look at the cookies sent back from the browser, Set-Cookie (also highlighted in yellow), you will see that the two CFHttp requests receive two different CFID and CFTOKEN values. Since a session is represented by its CFID/CFTOKEN combination, these two requests clearly have different sessions.
In order to maintain session on the subsequent CFHttp requests, we must need to maintain the same cookies. Therefore, we need to be able to parse the cookies out of the response header of one CFHttp request result and use them as parameters in subsequent CFHttp requests.
To do this, I created a ColdFusion user defined function (UDF) that would take a CFHttp result and parse the returned cookie strings into some sort of easily usable structure:
Launch code in new window » Download code as text file »
If we pass a CFHttp result to the above UDF and then CFDump out the structure, we get something like this:
| | | | ||
| | ![]() | | ||
| | | |
Once, we have our cookies parsed into a ColdFusion struct, we can send them as ColdFusion CFHttpParam values in subsequent CFHttp requests. For our next request, CFHttp request three, we are going to assume that request one and two have already been done and that the objGet from the second request is available for cookie parsing:
Launch code in new window » Download code as text file »
Running that code, we get the following CFHttp result object:
| | | | ||
| | ![]() | | ||
| | | |
Notice that the FileContent of the third request (highlighted in yellow) is "Hit Count: 2". The only way that the second hit count could be returned is if the sub application maintained the session from the second CFHttp request to the third. Notice also that in the result of the third CFHttp request, no cookies were sent back. ColdFusion only sets the cookies when the user's session begins. Since the session is maintained across page requests, ColdFusion does not require any further cookies to be set and therefore sends no cookie requests in the response header.
Download Code Snippet ZIP File
Comments (18) | Post Comment | Ask Ben | Permalink | Other Searches | Print Page
ColdFusion Application.cfc Tutorial And Application.cfc Reference
CFQuiz 2.13: Selecting N Random Elements From An Array In ColdFusion
Nice work
Posted by Shuns on May 24, 2007 at 6:10 PM
Thanks dude. Always fun to try something new out.
Posted by Ben Nadel on May 24, 2007 at 6:52 PM
Great... Great Article.. Ben...
Posted by Dav on May 25, 2007 at 1:51 AM
@Dav,
Thanks a lot. Please let me know if you can think of a good way I might expand upon this idea in a way that people might find useful.
Posted by Ben Nadel on May 25, 2007 at 7:03 AM
Interesting article. I hadn't ever thought about the idea that sessions wouldn't be maintained.
In response to expansion idea, how about a custom tag that is aware of it's own session and keeps it across requests. e.g. <cf_http session="mySession1">
Posted by Jeremy French on May 25, 2007 at 8:52 AM
@Jeremy,
That could be a cool idea. Let me play around with it a bit. Thanks for the suggestion.
Posted by Ben Nadel on May 25, 2007 at 8:56 AM
You shouldn't need to pass cookies, just pass the session info as a url parameter. You should be able to shorten your code to just one line:
<cfhttp
method="GET"
url="#urlSessionFormat(strURL)#"
useragent="#strUserAgent#"
result="objGet">
NOTE: If the urlSessionFormat() tag doesn't work, just manually append the required URL parameters (cfid/cftoken or jsessionid.)
Posted by Dan G. Switzer, II on May 25, 2007 at 9:41 AM
@Dan,
What you are saying is most definitely true, assuming we are talking about a ColdFusion application and that we already have the CFID / CFTOKEN values handy. But, what if this was calling an eBay site or something? Totally different technology and application scope. The returned page request will have nothing to do with the session of the code that is calling the CFHttp tag.
Posted by Ben Nadel on May 25, 2007 at 10:21 AM
I use cfhttp to communicate with another server through a web service, and I have to maintain the session. Since the web service is behind a single sign-on layer, I have to grab the cookies set by the SSO login, and pass it to the web service login. I have to keep sending the cookies with every call to the web service because cfhttp doesn't automatically keep track of the session.
I like the way you are handling the cookies. I am basically doing the same thing. I store my cookies in an array. Each array item is the name/value pair for the individual cookies. I send one value for the cookies in the cfhttp call like this:
<cfhttpparam type="header" name="Cookie" value="#ArraytoList(cookieArray';')#">
This way I don't have to loop through the structure collection every time.
Just adding my 2 cents.
Matthew
Posted by Matthew Abbott on May 25, 2007 at 11:59 AM
@Matt,
That is really cool. I didn't realize it would recognize the entire cookie string and parse it correctly (on the receiving end). This is MUCH easier than looping. Thanks!
Posted by Ben Nadel on May 30, 2007 at 5:57 PM
When ever I try to run your code I keep getting returned error: Variable GETRESPONSECOOKIES is undefined.
92 : CFHttp requests.
93 : --->
94 : <cfset objCookies = GetResponseCookies( objGet ) />
95 :
96 :
I created the GetResponseCookies.cfc file and I don't understand the error. I'm totally confused.
Posted by Jason on Dec 4, 2007 at 10:20 PM
@Jason,
GetResponseCookies() is a user defined function; it doesn't have to be in a CFC. The CFFunction tag just has to be included somewhere in your application the way any user defined function would be. It looks like you are just not including or defining the function before you try to utilize it.
Posted by Ben Nadel on Dec 5, 2007 at 7:05 AM
Hi Ben. One thing to note - this code chokes when a single cookie is set by the server (in which case, it comes back as a single string rather than a struct). A quick check to see what type of data is in the Set-Cookie item will fix this.
Posted by James Holmes on Feb 18, 2008 at 10:33 PM
@James,
Really?? That is so strange. I figured ColdFusion would have kept the same data type no matter what. That seems really lame that they don't automatically create a struct regardless of number of cookies.
Thanks for the heads up.
Posted by Ben Nadel on Feb 19, 2008 at 7:16 AM
I get a loop error on line 84 of this UDF. I think I'm running into the issue James mentions, though I'm not sure how to fix this.
Posted by Gernot on Jul 1, 2008 at 11:34 PM
@Gernot,
Make sure you have the most up to date CFC for this project:
http://www.bennadel.com/projects/cfhttp-session.htm
Posted by Ben Nadel on Jul 2, 2008 at 8:17 AM
Ben, have you considered putting this up at riaforge?
Posted by James Holmes on Jul 2, 2008 at 8:35 AM
@James,
I have considered it. It's just a matter of finding the time.
Posted by Ben Nadel on Jul 2, 2008 at 8:37 AM