mark nottingham

Friday Fun: I Hate Cookies

Friday, 27 October 2006

HTTP

There are plenty of reasons to hate HTTP Cookies, but there’s one thing that especially annoys me; their syntax.

Specifically, the Netscape spec allowed an “expires” field that contains the date the cookie should be discarded;

Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT

What’s wrong with that? Well, HTTP uses commas to delimit different instances of the same header, saying:

It MUST be possible to combine the multiple header fields into one “field-name: field-value” pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma.

Notice something about the above? It uses a comma inside of the date, without quoting the value. This makes it difficult for generic processors to handle the Set-Cookie header.

Still, it should be possible to parse a combined Set-Cookie header, as long as the implementation is careful.

If At First You Don’t Succeed, Bake Some More Cookies

RFC2109 tried to fix this by moving from expires to Max-Age, and also by allowing values to be quoted, making them easier to parse. That was in 1997.

Then, in 2000, RFC2965 stepped in and defined a new header, Set-Cookie2, containing a bunch more options than the old one.

My question is how well-supported these different mechanisms are by browsers, and do they support setting more than one cookie on the same header line?

To test this, I set up a simple page that sets a bunch of different cookies*;

Set-Cookie: NS=yes; expires=Wednesday, 01-Jan-10 0:0:00 GMT
Set-Cookie: NS_1=a; expires=Wednesday, 01-Jan-10 0:0:00 GMT, NS_2=b; expires=Wednesday, 01-Jan-10 00:00:00 GMT
Set-Cookie: RFC2109="yes"; Version="1"; Max-Age="60"
Set-Cookie: RFC2109_1="a"; Version="1"; Max-Age="60", RFC2109_2="b"; Version="1"; Max-Age="60"
Set-Cookie2: RFC2965="yes"; Version="1"; Max-Age="60"
Set-Cookie2: RFC2965_1="a"; Version="1"; Max-Age="60", RFC2965_2="b"; Version="1"; Max-Age="60"

Notice that each cookie style is set, and then set twice on the same line, to see if that’s supported.

Then, it tries to read them using JavaScript, and makes the raw Cookie request header available (in Apache’s CGI environment) from a separate link. There, you can see not only which cookies were set, but also which of the latter two include a $Version parameter to differentiate them from older-style cookies.

So Far, Not Good (updated)

You’d think that after so much time and two standards, we’d have this stuff nailed. Not so much.

  1. Safari 2, Firefox 2, IE6 and 7, and Opera 9 all work with Netscape and RFC2109 cookies, but none except Opera know anything about RFC2965. I didn’t have much expectation of broad adoption there, but it’s still disappointing.
  2. Opera and Safari both seem to be OK with combining cookies on the same line, but Firefox and IE only see the first one. This is a big pain for header libraries, and I’ve filed a bug where I can.
  3. Of all of them, only Opera sends the $Version parameter to indicate that it understands anything more recent than the Netscape spec.

So far, Opera seems like the only fully-featured browser cookie implementation out there. It would be interesting to test other cookie jars (e.g., in Python, Perl, Ruby).


8 Comments

Stefan Eissing said:

Netscape Cookies Supported: yes 1st combined: a, simple_2=b 2nd combined: b 1st combined w/expires: a 2nd combined w/expires: null RFC2109 Cookies Supported: “yes” 1st combined: “a” 2nd combined: null RFC2965 Cookies Supported: null 1st combined: null 2nd combined: null

Friday, October 27 2006 at 7:15 AM

Stefan Eissing said:

Does not look like it:

NS=yes; simple_1=a, simple_2=b; NS_1=a; RFC2109=”yes”; RFC2109_1=”a”

Just confirmed that IE7 returns exactly the same stuff. Seems that at least that part of the code was not touched.

Friday, October 27 2006 at 8:19 AM

Anne van Kesteren said:

I don’t know that much about all this but https://www.w3.org/mid/op.th17t2i6qrq7tp@nimisha.oslo.opera.com suggests that we, Opera, have implementation experience with RFC2965.

Saturday, October 28 2006 at 4:52 AM

graste said:

And as if that wouldn’t be enough, Opera employees like Yngve Nysæter Pettersen are working on new cookie specs:

“A new HTTP Cookie recipe” http://my.opera.com/yngve/blog/show.dml/519358

:)

Monday, October 30 2006 at 8:14 AM

Killbot Factory said:

Browser: Konqueror Engine: KHTML/3.5

Netscape Cookies Supported: yes 1st combined: a, simple_2=b 2nd combined: b 1st combined w/expires: a 2nd combined w/expires: null

RFC2109 Cookies Supported: “yes” 1st combined: “a” 2nd combined: null

RFC2965 Cookies Supported: “yes” 1st combined: null 2nd combined: null

Tuesday, December 12 2006 at 10:37 AM

Randolf Richardson said:

I’m using ModPerl 2 in Apache HTTPd 2.2 with the libapreq2 libraries to deal with cookies. The beauty of libraries such as these is that the implementation details are taken care of so all I have to deal with is one much simpler layer of abstraction. And as long as I keep my systems up-to-date (as I normally do anyway), new quirks that are occasionally introduced along with newer browser releases normally don’t create problems for my users.

I find that Opera provides the best information about all the cookies (Tools -> Advanced -> Cookies) that tend to accumulate over time. This is particularly useful when developing server-side Perl scripts that create/update cookies.

This article (above) was particularly interesting to me because although I’ve always known that different web browsers use a variety of approaches when dealing with cookies, I never had the time to get into the actual details. Thanks for posting this information; it should be helpful to me in troubleshooting occasional cross-browser cookie problems in the future.

Randolf Richardson - randolf@richardson.tw Vancouver, British Columbia, Canada

Tuesday, August 7 2007 at 7:06 AM