{"id":1036,"date":"2011-01-06T21:50:59","date_gmt":"2011-01-06T13:50:59","guid":{"rendered":"http:\/\/blog.lolyco.com\/sean\/?p=1036"},"modified":"2011-01-06T21:50:59","modified_gmt":"2011-01-06T13:50:59","slug":"expires-header-fails-max-age-works-rfc1123-compliance","status":"publish","type":"post","link":"https:\/\/blog.lolyco.com\/sean\/2011\/01\/06\/expires-header-fails-max-age-works-rfc1123-compliance\/","title":{"rendered":"Expires header fails, max-age works: RFC1123 compliance"},"content":{"rendered":"<p>While I was testing the <a href=\"http:\/\/blog.lolyco.com\/sean\/2011\/01\/06\/spider-my-simple-mobile-version\/\">mobile version of the search at spider.my<\/a> I noticed that my Nokia phone&#8217;s browser was briefly presenting an unformatted version of the page, then applying styles, then adding a small image. Doing that once would have been expected, but it shouldn&#8217;t have been doing it on subsequent requests of the search page. I serve my CSS files and images with an <a href=\"http:\/\/www.w3.org\/Protocols\/rfc2616\/rfc2616-sec14.html#sec14.21\">Expires header field<\/a> which should prompt user agents to re-use the previously loaded (and cached) CSS and images.<\/p>\n<p>I saw this article about <a href=\"http:\/\/www.mnot.net\/blog\/2007\/05\/15\/expires_max-age\">Expires versus the Cache-Control header&#8217;s max-age<\/a>, so I tried max-age and it worked! With max-age, my Nokia phone was no longer requesting the CSS and image it should already have cached. Doubt that Nokia (their phones just work really, really well) would have broken something so basic and a comment in mnot&#8217;s article about missing out a leading &#8216;0&#8217; on the hour part of the Expires date made me check my code again. Here&#8217;s what I was sending:<\/p>\n<p><code>Expires: Mon, 2 May 2011 01:53:37 GMT<\/code><\/p>\n<p>Nothing wrong with the hour, but there is an obvious candidate for a leading zero there. After changing the way my webserver formats dates (I had been formatting them to RFC1123\/822, which does specify 2-digit hours), so that it sent 2-digit day-of-month, it worked! The new Expires field looks like this:<\/p>\n<p><code>Expires: Mon, 02 May 2011 02:03:37 GMT<\/code><\/p>\n<p><a href=\"http:\/\/www.ietf.org\/rfc\/rfc822.txt\">RFC822<\/a> says you can specify 1 or 2 digits for the day-of-month part and <a href=\"http:\/\/www.ietf.org\/rfc\/rfc1123.txt\">RFC1123<\/a> (specified as the date format for the Expires header in <a href=\"http:\/\/www.ietf.org\/rfc\/rfc2616.txt\">RFC2616<\/a>) doesn&#8217;t alter that. Sending 1-digit day-of-month parts in a RFC1123 date <strong>is to specification<\/strong>.<\/p>\n<p>I just lodged a bug report with Nokia &#8211; it seems to me that their phones *should* be accepting the RFC1123-compliant Expires date. I wonder how many other user agents will have this issue, as it seems some people believe that the day-of-month part should have two digits &#8211; see <a href=\"http:\/\/stackoverflow.com\/questions\/1042179\/http-expires-header-not-respected-by-browser\">Dave Bauman&#8217;s comment at the foot of this StackOverflow thread.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>While I was testing the mobile version of the search at spider.my I noticed that my Nokia phone&#8217;s browser was briefly presenting an unformatted version of the page, then applying styles, then adding a small image. Doing that once would have been expected, but it shouldn&#8217;t have been doing it on subsequent requests of the [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14,3,35,64],"tags":[41,65,57],"class_list":["post-1036","post","type-post","status-publish","format-standard","hentry","category-broken","category-software","category-spidermy","category-useful","tag-http","tag-mobile","tag-web"],"_links":{"self":[{"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/posts\/1036","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/comments?post=1036"}],"version-history":[{"count":6,"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/posts\/1036\/revisions"}],"predecessor-version":[{"id":1048,"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/posts\/1036\/revisions\/1048"}],"wp:attachment":[{"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/media?parent=1036"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/categories?post=1036"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lolyco.com\/sean\/wp-json\/wp\/v2\/tags?post=1036"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}