Somebody was inquiring on a mailinglist why he would have a lot of errors in his *-event.log that looked like:

06/26 14:47:27 error Cannot create cookie: domain = .xxx.yyy

Amidst a number a theories a link to a blog post No Cookie for You!! surfaced as an explanation. An explanation that couldn’t possibly be true though (for reasons I will go into later this post). So now I was interested and I set out to get to the bottom of this problem on the commute home.

Cookies

In HTTP cookies are based on 2 headers send between the server and the browser. First, when the server wants to send a cookie, it uses a Set-Cookie header:

Set-Cookie: foo=bar; path=/; domain=.xxx.yyy; expires Mon, 09-Dec-2002 13:46:00 GMT

The Set-Cookie has a name-value pair with the name of the cookie and the value, and a bunch of attributes that allow the browser to determine whether or not to send the cookie back to the server on a subsequent request. And when a  browser wants to send a cookie back to a server, it sends a HTTP Cookie header:

Cookie: foo=bar

So what is going on

There are 2 problems with the eplanation provided in No Cookie for You!!

  1. the cs(Cookie) column in the webserver log does not describe the Set-Cookie header send from the server to the browser, but the Cookie header send from the browser to the server (always remember when reading HTTP logs: cs means client-to-server, sc means server-to-client). So instead of a (failed) attempt to set a cookie, it is actually is proof  that the browser sends a cookie back;
  2. not allowing a cookie to be set is meaningless in terms of the HTTP protocol. HTTP is a request-response protocol: the browser does a request, the server sends a response and that is it, there is no more communication. So even if the browser doesn’t like the cookie, it has no way to communicate that back to the server.

With this in mind I set out to reproduce the problem. First I constructed my own set of HTTP headers to send to the webserver:

GET /index.cfm HTTP/1.1
Host: localhost
Cookie: name=r2; expires=Tue, 02-Jul-2007 02:02:02 GMT;

Sending this set of headers to the webserver over telnet indeed produced an error in the *-event.log:

07/03 18:25:56 error Cannot create cookie: expires = Tue, 02-Jul-2007 02:02:02 GMT

So I set out to make a minimal reproduction. Expecting that the problem was somehow caused by improper escaping of the colons in the timestamp I tried to progressively reduce the number and complexity of the cookies until I ended up with:

GET /index.cfm HTTP/1.1
Host: localhost
Cookie: expires=T;

This still produced an error. Then I tried:

GET /index.cfm HTTP/1.1
Host: localhost
Cookie: e=T;

And I didn’t get an error anymore. And that is when I realized what was going on: the problem isn’t in the value or the escaping of the value, but in the name. Expires is treated as a reserved word because it is an attribute of a Set-Cookie header. Duh!!!

Reserved names

To complete the circle I ran a test with the cfccokie tag:

<cfcookie name="expires" value="test" />

And there I got the pretty grey and blue error message:

Cookie name EXPIRES is a reserved token

Further tests confirm that the following are all reserved names for cookies:

  • secure
  • domain
  • expires
  • path

And whenever CF receives a request with a cookie with one of those names, you get a line in your *-event.log with an error. I wonder if we can get CF to ignore that error without polluting the logfile.

11 Comments

  1. Raymond Camden says:

    So would this imply that someone is hitting my server and sending along a ‘bad’ cookie?

  2. mark kruger says:

    Jochem,

    I think you solved this mystery handily. I read the “no cookies…” blog and I was almost buying it - but the client vs server thing was bothering me too. I think you nailed it.

    -Mark

  3. Jochem says:

    Obviously somebody is hitting your server with bad cookies: you never set them so he shouldn’t send them.

    But looking at the three different specifications we have for cookies (the Netscape cookie proposal, RFC 2109 and RFC 2695) there is no reason why these cookie names should be reserved in ColdFusion. The name=value pair is always the first pair of a Set-Cookie header so there is no need for disambiguation.

  4. charlie arehart says:

    Great investigative work, Jochem. Thanks so much for sharing this. As for how to solve it, while we might await Adobe coming up with a solution, another thing we could do is have someone write a Java Servlet filter that looks for cookies with these names and drops them from the request before it’s passed on to CF. Wouldn’t be too hard.

    If anyone’s interested, you can find out more about servlet Filters (and their use with CF) in a Feb 2003 CFDJ article I did, “Fun with Filters”, at http://cfdj.sys-con.com/read/41574_p.htm.

  5. Terry Palmer says:

    Nice work Jochem. Seems my lack of knowledge of IIS log files led me to the wrong conclusion on “No Cookies For You”. The CS vs SC distinction does make sense now. There is still a point of confusion on my part though. Since setting “setclientcookies=false” in the cfapplication tag, we have no longer seen the “error Cannot create cookie:” errors in our logs. Do you have any insight as to why my fix would work for “blocking” reserved word cookies as it seems?

  6. Jochem says:

    My best theory is there is a user-agent out there that does incorrect parsing of Set-Cookie headers and assumes any name=value pair is a cookie, instead of just the first being the cookie and the others attributes. If that happens to be some sort of spider (or in your case perhaps a linkchecker from a wiki / CMS) that is an error that has very little impact on the results and thus a small chance of detection. And now you are not using any cookies at all they aren’t parsed incorrectly anymore and you don’t get the error in your logfiles anymore.

  7. Brad Wood says:

    Dang it Charlie, now you’ve turned me on to servlet filters! :) I’ve always known what they did, but never considered trying to write one. I think I’m gonna’ try to make a filter to get rid of certain cookies like you said– if for nothing else than to see how it would work. I’ll blog it if I can figure it out.

    ~Brad

  8. Jochem says:

    I filed an enhancement request with Adobe with the following text:

    Ignore logging of “domain”, “expires” etc. cookies

    When CF (JRun?) receives a request with cookies named “domain”, “expires” etc. it logs an error in *-event.log. This needlessly clutters the logfile with something that isn’t really an error (the Netscape cookie proposal, RFC 2109 and RFC 2695 all allow those cookie names). Please allow us to switch off logging of these cookies (and disable this logging by default).

  9. Brad Wood says:

    Jochem, I’m in the process of blogging my finds now, but the short story is I successfully wrote a servlet filter to remove cookies from the httpServletRequest object before ColdFusion got it, but it didn’t work becuase JRUN is where the cookies get parsed and the log files are appended BEFORE any servlet filters are run. I tracked it down to the javax.servlet.http.Cookie class (which is thankfully open source) and sure enough, an IllegalArgumentException error is thrown when the cookie name is a in a list of reserved names. Check out the code at http://kickjava.com/src/javax/servlet/http/Cookie.java.htm.

    The best Adobe could do would be to not log errors returned by the Cookie class constructor. In the mean time, I posted this question to the Sun Java forum to see if anyone could provide some history. http://forum.java.sun.com/thread.jspa?threadID=5313146

    ~Brad

  10. Brad Wood says:

    Here’s my latest solution to this problem. So far it works locally on my machine.

    http://www.codersrevolution.com/index.cfm/2008/7/15/No-Cookie-For-You-Second-Solution