EDIT: Unfortunately, I was wrong about this! Please see Jason's comment below.
As you know, ColdFusion makes it pretty easy to get cookies sent to the page in the current request. All cookies are stored in a simple structure that you can either dump or simply loop over.
<cfloop item="c" collection="#cookie#">
<cfoutput>cookie[#c#] = #cookie[c]#<br/></cfoutput>
</cfloop>
But while this gives you the name and value of all cookies, it doesn't tell you anything else about the cookie, like it's expiration, path, or other values. For that, you have to get into the request at the Java level. Luckily, ColdFusion makes this simple too:
<cfset cookies = getPageContext().getRequest().getCookies()>
Where did this line of code come from? getPageContext() is a CFML function that returns the underlying Java PageContext object. From some Googling, I found that I could get the Request data from that Page object and then get an array of cookies using getCookies. Pretty simple, right? Each cookie object has all it's values available via simple get methods. You can see the documentation for that here. Here is a trivial sample that just loops over them and prints out some of the values.
<cfloop index="c" array="#cookies#">
<cfoutput>
Name=#c.getName()#<br/>
Value=#c.getValue()#<br/>
Path=#c.getPath()#<br/>
Domain=#c.getDomain()#<br/>
MaxAge=#c.getMaxAge()#<br/>
<p>
</cfoutput>
<cfdump var="#c#">
</cfloop>
<cfset cookies = getPageContext().getRequest().getCookies()>
Archived Comments
Works on CF8. Thanks for the tip Ray.
Cool tip to share, Ray. Thanks.
One thing folks should consider, though, is that there could be a difference in what gets shown in that list, compared to the cookies scope itself. The cookie scope will reflect cookies that CF code sets (such as would be done implicitly by the CFAPPLICATION tag enabling clientmanagement or session management, or via application.cfc's this.clientmanagement/this.sessionmanagement).
But the getpagecontext().getRequest() really gets the request as it was sent TO the page, not anything that was set ON the page. It's a subtle point, but I've seen people trying to troubleshoot problems and they didn't keep this in mind, and they were misled thinking the cookie scope showed only what was sent TO the page.
So code like yours is helpful to make sure one sees clearly what is sent. A dump of the cgi.http_cookie would also do it, though just like your discussion of the cookie scope, it too does not show the other metadata like expiration, path, etc.
Hope that's helpful.
One last point: that getpagecontext is indeed a treasure-trove of interesting possibilities that folks may want to explore. Some may recall I pointed out its use with server-side redirects (forwards), in an article in the CFDJ back in 2002. For those who may be interested, it's still available online, at http://www.carehart.org/art....
Excellent point Charlie, thanks!
Does the cookie value need to the URLDecoded? Logically,if the value contains the string ';path=' , outside case I know but you get the point, that would interfere with the intended path spec for the cookie, so the semicolon must be escaped.
Experimentally, if I use cfcookie to set a cookie with the value "asdf qwer <poi>;HTTPOnly", the code above shows the whitespace, brackets and semicolon as URLEncoded, but cfdumping the cookie scope shows the decoded version. I see the same behavior if I use cfheader to set a cookie manually, and URLEncode the value portion of it (only, not the whole spec string).
I've been looking for an official spec on what needs to be escaped and how, haven't come up with anything solid. Did find this statement from Nicholas C. Zakas:
"The commonly held belief is that cookie values must be URL-encoded, but this is a fallacy even though it is the de facto implementation. The original specification indicates that only three types of characters must be encoded: semicolon, comma, and white space. The specification indicates that URL encoding may be used but stops short of requiring it. The RFC makes no mention of encoding whatsoever. Still, almost all implementations perform some sort of URL encoding on cookie values. In the case of name=value formats, the name and value are typically encoded separately while the equals sign is left as is."
That's here: http://www.nczonline.net/bl...
So my tentative conclusion is that cookie values do need to be URLEncoded, and the code above should decode them. That may be specific to ColdFusion, or not; according to the above, that's the de facto spec, which CF seems to have followed, in both directions.
Any other thoughts on this?
Also, don't know what to make of this, but I'm not seeing getDomain(), getPath(), or getMaxAge() return anything when there's actually a domain, path, and expiration set.
I have some cookies set that a) show a domain, path, and expiration in Firefox's page info dlg, b) show different values in the Firebug Net panel request headers section, and c) have different values in different locations on the same domain according to cf.
That makes me fairly confident that they really do have domain, path and exipration specs, but the code above shows blank for all three. Maybe those other infos are thought to be the client's business, not the server's so they don't get sent to the server? But then why do these methods exist in javax.servlet.http.Cookie? Same behavior on ACF and Railo.
Don't get it.
Just to clarify your first comment - cookie values should be encoded, but as you said, CF is handling this for us. Agreed?
As for getDomain/etc failing... no idea on that one. :(
On the set side, if you use cfcookie it's handled for you, but not if you use cfheader. On the get side, if you read the values from the cf cookie scope it's handled, but not if you use the java methods shown here.
But unless I'm doing or thinking something silly, the java methods don't actually return any of the extra metadata that would make them more attractive than native cf anyway, so that may be moot.
Age would be useful.
Cookie metadata like Domain, Path and Max age are set in a response when the cookie is first created and then sent to the client, which stores them. To my knowledge, all of that metadata is then forgotten by the server and will *never* show up in an HTTP request.
When the client sends cookies back to the server, that metadata is not sent along. Only the name and value are sent. That is my those getters return blank.
To my knowledge there is no way, nor any point, in trying to get that data from the cookies. Perhaps you could do it on the same request/response where the cookie is set, but not after that.
Jason is correct. This is not unique to ColdFusion, but rather the way cookies work. I found this on a ASP.NET site:
http://msdn.microsoft.com/e...
"The browser is responsible for managing cookies, and the cookie’s expiration time and date help the browser manage its store of cookies. Therefore, although you can read the name and value of a cookie, you cannot read the cookie’s expiration date and time. When the browser sends cookie information to the server, the browser does not include the expiration information. (The cookie’s Expires property always returns a date-time value of zero.) If you are concerned about the expiration date of a cookie, you must reset it, which is covered in the "Modifying and Deleting Cookies" section."
Thanks for the correction Jason. I'm going to edit the blog post to ensure folks see your comment.
Hi Ray. Thanks for another very informative post. Can you tell me where Coldfusion cookies are stored by default. Am I correct in thinking that SESSION variables are stored on the Application server and Coldfusion COOKIE variables are stored in the client's browser?
Cookies are stored in the browser, CF is just giving you a way to read them and set them. But they are stored in the browser. Session variables have nothing to do with cookies, outside of the fact that cookies are used to identify you. So 2 cookies note you as Charles and server says, "Charles' session values are so and so."
Thanks Ray for explaining this. I really needed this clarifying after nearly a decade of CFML development. So, if I am using a server cluster, and one of my servers fails, I can use an id cookie to retrieve my session from a custom shared session database. I can store my users' session variables in a DB and then retrieve them, if one of my servers fails. This will allow me to keep my users' session alive across the cluster?
I want to say, but I'm not 100% sure, that recent versions of CF supported session replication, but I honestly don't know. I'd Google for that "session replication coldfusion" and see.
Jason. Is this why the maxAge() for all my cookies returns -1, when I know that this clearly is not the correct value?