Yesterday i had to make for a client a script that will
- connect to a site
- login
- move to other internal page from where data should be taken
So what the usual process would be in such a case?
- make a CFHTTP request
- using the cookies from previous step, if any exists, make the CFHTTP call with login credentials
- using the cookies from previous step (here should be present session cookies), make the CFHTTP call to the internal page
- do with the data whatever you need
Everything looks fine so far and in most of the cases works as supposed, but NOT everytime. Sometimes on step 3 instead of going to the internal page it "lose the session" and as result you get there the login page instead. This is exactly what happened for me for this particular client. I have no idea what the problem is but i remember such an issue even back in 2003. I tried all i could think of: passing cookies in CFHTTPPARAMs, puttin the heder with cookies and all in USERAGENT parameter of CFHTTP (yes this one looks a bit weird, but i remember this solving the problem for some sites within last 7-8 years). Nothing helped. Then i tried CFX_HTTP that i was using years ago in such situations and of course everything worked great.
So the question is - WHAT THE HECK ?!
After so many years we still should have such problems with CFHTTP? Weird.
For this particular client it happened there to be a 64-bit system, so instead of CFX_HTTP i had to rewrite the script to use CFX_HTTP5. But this doesn't change the fact that it wasn't possible to be done with CFHTTP itself. Googling for solutions from other's experience didn't help. So i thought - if ColdFusion is Java, why not try a Java solution?
Another half day in googling, trying, testing and i've created a function that not only do a GET HTTP connection, but also works fine for the situation described above. It's far from being universal enough, but it worked well for my situation. So if anyone need it, here is the code:
<cffunction name="makeHTTPRequest" output="yes" returntype="any">
<cfargument name="requestURL" required="Yes" type="any">
<cfargument name="requestCookies" required="No" type="any" default="">
<cfset var result = StructNew()>
<cfset var i = 1>
<cfset var urlConnection = createObject("java", "java.net.URL").init("#arguments.requestURL#").openConnection()>
<cfset var inputReader = "">
<cfset var bufferedReader = "">
<cfif Len(arguments.requestCookies)>
<cfset urlConnection.setRequestProperty("Cookie", arguments.requestCookies)>
</cfif>
<cfset urlConnection.connect()>
<cfset inputReader = createObject("java", "java.io.InputStreamReader").init(urlConnection.getInputStream())>
<cfset bufferedReader = createObject("java", "java.io.BufferedReader").init(inputReader)>
<cfset result.headers = "">
<cfset result.headerNoCookie = "">
<cfset result.cookies = "">
<cfset result.content = "">
<cfscript>
do
{
headerName = urlConnection.getHeaderFieldKey(i);
lineCheck = IsDefined("headerName");
if (lineCheck)
{
if (Len(result.headers))
{
result.headers = result.headers & "|" & headerName & "=" & urlConnection.getHeaderField(i);
}
else
{
result.headers = headerName & "=" & urlConnection.getHeaderField(i);
}
if (headerName.equals("Set-Cookie"))
{
result.cookies = result.cookies & ListGetAt(urlConnection.getHeaderField(i), 1, ";") & "; ";
}
else
{
if (Len(result.headerNoCookie))
{
result.headerNoCookie = result.headerNoCookie & "|" & headerName & "=" & urlConnection.getHeaderField(i);
}
else
{
result.headerNoCookie = headerName & "=" & urlConnection.getHeaderField(i);
}
}
}
i = i + 1;
} while(lineCheck);
do
{
line = bufferedReader.readLine();
lineCheck = IsDefined("line");
if(lineCheck)
{
result.content = result.content & line;
}
} while(lineCheck);
</cfscript>
<cfreturn result>
</cffunction>
It takes at input the URL and optionally a string with cookies and returns a structure with 4 keys headers, headerNoCookie, cookies, content
And here is an usage example:
<!--- make first request to firstURL with login credentials --->
<cfset firstCall = makeHTTPRequest(firstURL)>
<!--- make second request to secondURL using the cookiens from the first request --->
<cfset secondCall = makeHTTPRequest(secondURL, firstCall.cookies)>
Hope it will help somebody.
HAPPY CODING !!!
P.S.: If anyone want to comment on it, please do so.