{"id":2014,"date":"2010-09-01T22:45:55","date_gmt":"2010-09-01T20:45:55","guid":{"rendered":"http:\/\/daniel.haxx.se\/blog\/?p=2014"},"modified":"2010-09-03T23:15:02","modified_gmt":"2010-09-03T21:15:02","slug":"testing-2-digit-year-numbers-in-cookies","status":"publish","type":"post","link":"https:\/\/daniel.haxx.se\/blog\/2010\/09\/01\/testing-2-digit-year-numbers-in-cookies\/","title":{"rendered":"Testing 2-digit year numbers in cookies"},"content":{"rendered":"<p>In the current work of the <a href=\"https:\/\/datatracker.ietf.org\/wg\/httpstate\/charter\/\">IETF http-state working group<\/a>, we&#8217;re documenting how cookies work. The question came up how browsers and clients treat years in &#8216;expires&#8217; strings if the year is only specified with two digits. And more precisely, <strong>is 69 in the future or in the past?<\/strong><\/p>\n<p>I decided to figure that out. I setup a little CGI that can be used to check what your browser thinks:<\/p>\n<blockquote><p><a href=\"http:\/\/daniel.haxx.se\/cookie.cgi\">http:\/\/daniel.haxx.se\/cookie.cgi<\/a><\/p><\/blockquote>\n<p>It sends a single cookie header that looks like:<\/p>\n<blockquote><p>Set-Cookie: testme=yesyes; expires=Wed Sep\u00c2\u00a0 1 22:01:55 69;<\/p><\/blockquote>\n<p>The CGI script looks like this:<\/p>\n<blockquote>\n<pre>print \"Content-Type: text\/plain\\n\";\r\nprint \"Set-Cookie: testme=yesyes; expires=Wed Sep\u00c2\u00a0 1 22:01:55 69;\\n\";\r\nprint \"\\nempty?\\n\";\r\nprint $ENV{'HTTP_COOKIE'};<\/pre>\n<\/blockquote>\n<p>You see that it prints the Cookie: header, so if you reload that URL you should see &#8220;testme=yesyes&#8221; being output if the cookie is still there. <em>If the cookie is still there, your browser of choice treats the date above as a date in the future<\/em>.<\/p>\n<p>So, what browsers think 69 is in the future and what think 69 is in the past? Feel free to try out more browsers and tell me the results, this is the list we have so far:<\/p>\n<p><strong>Future<\/strong>:<\/p>\n<p style=\"padding-left: 30px;\">Firefox v3 and v4 (year 2069)<br \/>\ncurl (year 2038)<br \/>\nIE 7 (year 2069)<br \/>\nOpera (year 2036)<br \/>\nKonqueror 4.5<br \/>\nAndroid<\/p>\n<p><strong>Past<\/strong>:<\/p>\n<p style=\"padding-left: 30px;\">Chrome (both v4 and v5)<br \/>\nGnome Epiphany-Webkit<\/p>\n<p>Thanks to my friends in #rockbox-community that helped me out!<\/p>\n<p>(this info was originally <a href=\"http:\/\/www.ietf.org\/mail-archive\/web\/http-state\/current\/msg00941.html\">posted to the httpstate mailing list<\/a>)<\/p>\n<h2>Beyond just &#8220;69&#8221;<\/h2>\n<p>(this section was added after my first post)<\/p>\n<p>After having done the above basic tests, I proceeded and wrote a slightly more involved test that sets 100 cookies in this format:<\/p>\n<blockquote>\n<pre>Set-Cookie: test$yy=set; expires=Wed Oct\u00c2\u00a0 1 22:01:55 $yy;<\/pre>\n<\/blockquote>\n<p>When the user reloads this page, the page prints all &#8220;test$yy&#8221; cookies that get sent to the server. The results with the various browsers is very interesting. <em>These are the ranges different browsers think are future<\/em>:<\/p>\n<ul>\n<li>Firefox: 21 &#8211; 69 (Safari and Fennec and MicroB on n900) [*]<\/li>\n<li>Chrome: 10 &#8211; 68<\/li>\n<li>Konqueror: 00 &#8211; 99 (and IE3, Links, Netsurf, Voyager)<\/li>\n<li>curl: 10 &#8211; 70<\/li>\n<li>Opera: 41 &#8211; 69 (and Opera Mobile) [*]<\/li>\n<li>IE8: 31 &#8211; 79 (and slimbrowser)<\/li>\n<li>IE4: 61 &#8211; 79 (and IE5, IE6)<\/li>\n<li>Midori: 10 &#8211; 69 (and IBrowse)<\/li>\n<li>w3m: 10 &#8211; 37<\/li>\n<li>AWeb: 10 &#8211; 77<\/li>\n<li>Nokia 6300: [none]<\/li>\n<\/ul>\n<p>[*] = Firefox has a default limit of 50 cookies per host which is the explanation to this funny range. When I changed the config &#8216;network.cookie.maxPerHost&#8217; to 200 instead (thanks to Dan Witte), I got the more sensible and expected range 10 &#8211; 69. Opera has the similar thing, it has a limit of 30 cookies by default which explains the 41-69 limit in this case. It would otherwise get 10-69 as well. (thanks to Stanislaw Adrabinski). I <em>guess<\/em> that the IE8 range is similarly restricted due to it using a limit of 50 cookies per host and an epoch at 1980.<\/p>\n<p>I couldn&#8217;t help myself from trying to parse what this means. The ranges can roughly be summarized like this:<\/p>\n<p>0-9: mostly in the past<br \/>\n10-20: almost always in the future except Firefox<br \/>\n21-30: even more likely to be in the future except IE8<br \/>\n31-37: everyone but opera thinks this is the future<br \/>\n38-40: now w3m and opera think this is the past<br \/>\n41-68: everyone but w3m thinks this is the future<br \/>\n69: Chrome and w3m say past<br \/>\n70: curl, IE8, Konqueror say future<br \/>\n71-79: IE8 and Konqueror say future, everyone else say past<br \/>\n80-99: Konqueror say future, everyone else say past<\/p>\n<p>How to test a browser near you:<\/p>\n<ol>\n<li>goto <a href=\"http:\/\/daniel.haxx.se\/cookie2.cgi\">http:\/\/daniel.haxx.se\/cookie2.cgi<\/a><\/li>\n<li>reload once<\/li>\n<li>the numbers shown on the screen is the year numbers the browsers consider<br \/>\nto be the future as described above<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>In the current work of the IETF http-state working group, we&#8217;re documenting how cookies work. The question came up how browsers and clients treat years in &#8216;expires&#8217; strings if the year is only specified with two digits. And more precisely, is 69 in the future or in the past? I decided to figure that out. &hellip; <a href=\"https:\/\/daniel.haxx.se\/blog\/2010\/09\/01\/testing-2-digit-year-numbers-in-cookies\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Testing 2-digit year numbers in cookies<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,45],"tags":[216,86,226,249,426],"class_list":["post-2014","post","type-post","status-publish","format-standard","hentry","category-curl","category-web","tag-cookies","tag-firefox","tag-ie","tag-ietf","tag-web"],"_links":{"self":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/2014","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/comments?post=2014"}],"version-history":[{"count":23,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/2014\/revisions"}],"predecessor-version":[{"id":2026,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/2014\/revisions\/2026"}],"wp:attachment":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media?parent=2014"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/categories?post=2014"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/tags?post=2014"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}