Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Jay Vanderlyn and Mike Shea and Graeme Rae
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Jay Vanderlyn , Mike Shea@sheaman ) , and Graeme Rae@graemerae )

Exploring The CFCookie encodeValue Attribute In ColdFusion

By Ben Nadel on
Tags: ColdFusion

For the most part, Cookies are one of those things that "just work" in a ColdFusion application. There are some caveats around preserveCase and the way that structDelete() interacts with the Cookie scope. But, for the most part, cookies just do what they're supposed to do. As such, when James Moberg pointed out that ColdFusion 10 introduced an "encodeValue" attribute to the CFCookie tag, I wasn't exactly sure what it did. So, I wanted to do a little exploration.


 
 
 

 
 
 
 
 

To explore this, I created a simple page that would generate a string of ASCII characters and then try to store it in two cookies - one with encoding (the default behavior) and one without encoding:

  • <cfscript>
  •  
  • value = "";
  •  
  • // Build up the cookie value using ASCII values. We're making sure to go above the
  • // the core 127 ASCII characters to see who encoding interacts with higher ASCII.
  • // --
  • // NOTE: We are tarting at 9 since, if we start at a lower value, the cookie tag
  • // will throw the error, "Control character in cookie value or attribute.".
  • for ( i = 9 ; i <= 165 ; i++ ) {
  •  
  • value &= chr( i );
  •  
  • }
  •  
  • // Set cookie with encoding (the default behavior).
  • cfcookie(
  • name = "withEncoding",
  • value = value,
  • preserveCase = true
  • );
  •  
  • // Set cookie WITHOUT encoding (the non-default behavior).
  • cfcookie(
  • name = "withoutEncoding",
  • value = value,
  • preserveCase = true,
  • encodeValue = false
  • );
  •  
  • </cfscript>

I started at ASCII character 9 because anything lower than that would throw the following ColFusion error:

Control character in cookie value or attribute.

... and, I wanted to make sure that I went above the core 128 ASCII characters; so, I went up to 165. But, I figured anything higher than that would likely be treated in the same manner that 128-165 was treated; so, no need to add noise.

Once I had this page, I opened up Chrome to look at the network traffic. As expected, I saw two "Set-Cookie" headers (I'm adding the line breaks):

Set-Cookie:withEncoding=%09%0B%0C%0E%0F%10%11%12%13%14%15%
16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28
%29%2A%2B%2C%2D%2E%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDE
FGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E%5F%60abcdefghijklmnopqr
stuvwxyz%7B%7C%7D%7E%7F%C2%80%C2%81%C2%82%C2%83%C2%84%C2
%85%C2%86%C2%87%C2%88%C2%89%C2%8A%C2%8B%C2%8C%C2%8D%C2%8E
%C2%8F%C2%90%C2%91%C2%92%C2%93%C2%94%C2%95%C2%96%C2%97%C2
%98%C2%99%C2%9A%C2%9B%C2%9C%C2%9D%C2%9E%C2%9F%C2%A0%C2%A1
%C2%A2%C2%A3%C2%A4%C2%A5; Path=/

Set-Cookie:withoutEncoding="!\"#$%&'()*+,-./0123456789:;
<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrst
uvwxyz{|}~ %80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E
%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1
%A2%A3%A4%A5"; Version=1; Path=/

As you can see, the cookie set with [encodeValue=false] encoded far fewer characters. However, both cookie values encoded higher ASCII values. But, you may noticed that they encoded them using two different approaches. The default behavior - with encoding - is to encode the cookie value for URI usage. The encoded value is compatible with JavaScript's decodeURIComponent() method.

The non-encoded value looks like it encoded the higher ASCII values with their hexadecimal equivalents. I believe that this approach is compatible with JavaScript's unescape() method (but not with the decodeURIComponent() method).

Now, what's really interesting is that if I make subsequent requests, you can clearly see that the non-encoded value is not passed back to the server. And, in fact, if I log the document's cookie string, the non-encoded value is missing:


 
 
 

 
 encodeValue in ColdFusion CFCookie tag prevents the URL-encoding of cookie values. 
 
 
 

As you can see, the "withoutEncoding" cookie is not getting passed-back in the Request Headers.

Now, this doesn't always happen with the non-encoded cookie. If you have a non-encoded cookie string that only has alpha-numeric values (and other "safe" lower ASCII values), it will get passed back. But, once you start including HEX-encoded characters in the non-encoded cookie value, the work-flow starts to break.

The default behavior of the CFCookie tag, in ColdFusion, is to URL-encode cookie values. And, that seems to work really well. You can override that behavior now with the encodeValue attribute; but, I can't think of a reason, off-hand, that you would want to do that. It only seems to make things unstable. If anyone has a use-case for this, I'd love to hear about it.




Reader Comments

Ben,
Did not think about that in a long while.
I agree, you have to go a little far out for use-cases on unencoded cookies. I can think of two:
a) If you use front end JS to call back to another service in the same domain without going through CF, the expected encoding could throw things off.
b) pure space. Long cookies strings (>2KB) could be marked by content filters and firewalls as hack attempts

Cheers,
B.

Reply to this Comment

@Bilal,

Thinking about space is interesting. But, I go back and forth on this. If you look at the encoding, neither approaches actually encode your standard values (ie, a-zA-Z0-9). So, if you're only using basica alpha-numeric data, there's not going to be much difference.

Anyway, good thinking... definitely a funky problem-space to consider.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.