Subject: Re: #227: HEAD and Caches

From: Mark Nottingham <[email-masked]>
Date: Fri, 2 Mar 2012 17:19:54 +1100

On 16/02/2012, at 6:25 PM, Henrik Nordström wrote:

> mån 2012-02-13 klockan 15:45 +1100 skrev Mark Nottingham:
>> New:   
>> 
>> The response to a HEAD request is cacheable; it MAY be used to satisfy
>> subsequent HEAD requests. 
> 
> You just lost the property of HEAD updating GET responses. This is a
> very intentional property.
> 
> HEAD response == GET response minus body. As such it has the same cache
> metadata update properties as 304 responses or merge of 204 responses.

Proposal:

Index: p2-semantics.xml
===================================================================
--- p2-semantics.xml	(revision 1553)
+++ p2-semantics.xml	(working copy)
@@ -85,6 +85,7 @@
   <!ENTITY p6-heuristic               "<xref target='Part6' x:rel='#heuristic.freshness' xmlns:x='http://purl.org/net/xml2rfc/ext'/>">
   <!ENTITY p6-explicit                "<xref target='Part6' x:rel='#calculating.freshness.lifetime' xmlns:x='http://purl.org/net/xml2rfc/ext'/>">
   <!ENTITY p6-invalid                 "<xref target='Part6' x:rel='#invalidation.after.updates.or.deletions' xmlns:x='http://purl.org/net/xml2rfc/ext'/>">
+  <!ENTITY p6-head                 "<xref target='Part6' x:rel='#head.effects' xmlns:x='http://purl.org/net/xml2rfc/ext'/>">
 ]>
 <?rfc toc="yes" ?>
 <?rfc symrefs="yes" ?>
@@ -1035,12 +1036,8 @@
 </t>
 <t>
    The response to a HEAD request is cacheable and &MAY; be used to satisfy
-   a subsequent HEAD request; see &caching;. It also &MAY; be used to update a previously cached
-   representation from that resource; if the new field values
-   indicate that the cached representation differs from the current representation (as
-   would be indicated by a change in Content-Length, ETag
-   or Last-Modified), then the cache &MUST; treat the cache entry as
-   stale.
+   a subsequent HEAD request. It also has potential side effects on
+   previously stored responses to GET; see &p6-head;.
 </t>
 <t>
    Bodies on HEAD requests have no defined semantics. Note that sending a body

Index: p6-cache.xml
===================================================================
--- p6-cache.xml	(revision 1553)
+++ p6-cache.xml	(working copy)
@@ -1013,7 +1013,7 @@
    </list>
 </t>
 
-<section anchor="freshening.responses" title="Freshening Responses">
+<section anchor="freshening.responses" title="Freshening Responses with 304 Not Modified">
 <t>
    When a cache receives a 304 (Not Modified) response and already has one
    or more stored 200 (OK) responses for the same cache key, the cache needs
@@ -1055,8 +1055,40 @@
 </t>
 </section>
 
+<section anchor="head.effects" title="Updating Caches with HEAD Responses">
+<t>
+   A response to the HEAD method is identical to what an equivalent request
+   made with a GET would have been, except it lacks a body. This property
+   of HEAD responses is used to both invalidate and update cached GET
+   responses.
+</t>
+<t>
+   If one or more stored GET responses can be selected (as per <xref
+   target="caching.negotiated.responses"/>) for a HEAD request, and the
+   Content-Length, ETag or Last-Modified value of a HEAD response differs from
+   that in a selected GET response, the cache &MUST; consider that selected
+   response to be stale.
+</t>
+<t>
+   If the Content-Length, ETag and Last-Modified values of a HEAD response
+   (when present) are the same as that in a selected GET response (as per
+   <xref target="caching.negotiated.responses"/>), the cache SHOULD update the
+   remaining headers in the stored response using the following rules:
+   <list style="symbols">
+      <t>delete any Warning header fields in the stored response with
+         warn-code 1xx (see <xref target="header.warning" />);</t>
+      <t>retain any Warning header fields in the stored response with
+         warn-code 2xx; and,</t>
+      <t>use other header fields provided in the 304 response to replace
+         all instances of the corresponding header fields in the stored
+         response.</t>
+   </list>
+</t>
+
 </section>
 
+</section>
+
 <section anchor="invalidation.after.updates.or.deletions" 
    title="Request Methods that Invalidate">
 <t>

--
Mark Nottingham   http://www.mnot.net/

---

From: Erlend Hamnaberg <[email-masked]>
Date: Fri, 2 Mar 2012 09:01:33 +0100

2012/3/2 Mark Nottingham <[email-masked]>

>   <!ENTITY p6-heuristic               "<xref target='Part6'
> x:rel='#heuristic.freshness' xmlns:x='http://purl.org/net/xml2rfc/ext'/>">
>   <!ENTITY p6-explicit                "<xref target='Part6'
> x:rel='#calculating.freshness.lifetime' xmlns:x='
> http://purl.org/net/xml2rfc/ext'/>">
>   <!ENTITY p6-invalid                 "<xref target='Part6'
> x:rel='#invalidation.after.updates.or.deletions' xmlns:x='
> http://purl.org/net/xml2rfc/ext'/>">
> +  <!ENTITY p6-head                 "<xref target='Part6'
> x:rel='#head.effects' xmlns:x='http://purl.org/net/xml2rfc/ext'/>">
>  ]>
>  <?rfc toc="yes" ?>
>  <?rfc symrefs="yes" ?>
> @@ -1035,12 +1036,8 @@
>  </t>
>  <t>

Copy/paste bug in the following paragraph?

>    title="Request Methods that Invalidate">
Good clarifications.

In a related note: Is it allowed for a cache to rewrite a HEAD request to a
GET if there previously is no entity stored for that request?
Maybe there should be some text on that, or is that an implementation
detail?

--
Erlend Hamnaberg

---

From: Mark Nottingham <[email-masked]>
Date: Fri, 2 Mar 2012 21:09:53 +1100

>    title="Request Methods that Invalidate">

Ah, yes - thanks.

> Good clarifications.
> 
> In a related note: Is it allowed for a cache to rewrite a HEAD request to a GET if there previously is no entity stored for that request? 
> Maybe there should be some text on that, or is that an implementation detail?

It certainly isn't prohibited, but I tend to think that's an optimisation, not a specified behaviour. 

Cheers,

---

From: Willy Tarreau <[email-masked]>
Date: Fri, 2 Mar 2012 12:24:21 +0100

Hi Mark,

> It certainly isn't prohibited, but I tend to think that's an optimisation, not a specified behaviour. 

Even if it's not specified, maybe we should have one line which says that
it's valid to use GET where HEAD was expected if the client finds any
benefit in doing so. Well, maybe we already have it, it's just that I
have not actively looked for this.

Regards,
Willy

---

From: Henrik Nordström <[email-masked]>
Date: Fri, 02 Mar 2012 13:04:25 +0100

Looks good to me, if correcting the copy-paste 304 reference.

---

From: Henrik Nordström <[email-masked]>
Date: Fri, 02 Mar 2012 13:04:50 +0100

fre 2012-03-02 klockan 09:01 +0100 skrev Erlend Hamnaberg:

> In a related note: Is it allowed for a cache to rewrite a HEAD request
> to a GET if there previously is no entity stored for that request? 

I see no reason why not. HEAD and GET are semantically equivalent, only
differing in if the client wants the response entity or just it's
metadata.

Regards
Henrik

---

From: Henrik Nordström <[email-masked]>
Date: Fri, 02 Mar 2012 13:14:02 +0100

> optimisation, not a specified behaviour. 

Yes, it is an optimization. It would certainly be wrong to specify that
caches SHOULD change HEAD to GET.

If anything needs to be said on the topic then perhaps further stressing
the fact that HEAD and GET are semantically equivalent. But unless text
have weakened significantly in this compared to 2616 then I see no
reason why spend any effort on that.

Regards
Henrik

---

From: Henrik Nordström <[email-masked]>
Date: Fri, 02 Mar 2012 19:52:54 +0100

> have not actively looked for this.

It is not explicitly stated. But not sure it's needed.

The specs is pretty clear on how HEAD and GET (do not) differ. 

Regards
Hen

---

From: Mark Nottingham <[email-masked]>
Date: Sat, 3 Mar 2012 11:13:25 +1100

OK, I'm going to incorporate for -19 (with the correction).