Subject: What are "appropriate Cache-Control or Expires header fields"

From: "Brian Smith" <[email-masked]>
Date: Mon, 12 Oct 2009 20:22:58 -0500

What, precisely, must the Cache-Control or Expires header fields contain in
order to make a response to a POST, a 302 response, a 303 response, or a 307
response cacheable? This seems to not be specified anywhere in the
specification.

The definition of POST says: "Responses to this method are not cacheable,
unless the response includes appropriate Cache-Control or Expires header
fields."

The definitions of 302 Found and 307 Temporary Redirect both say: "This
response is only cacheable if indicated by a Cache-Control or Expires header
field."

The definition of 303 See Other says: "Response SHOULD NOT be cached unless
it is indicated as cacheable by Cache-Control or Expires header fields."

Thanks,
Brian

---

From: Mark Nottingham <[email-masked]>
Date: Wed, 14 Oct 2009 17:35:18 +1100

POST caching is still a work in progress; p6 now accommodates it, but  
we haven't yet modified the definition of POST itself. Stay tuned...

WRT 302 / 307 / 303 -- the use of the term 'cacheable' is cloudy here,  
but otherwise it's pretty straightforward; are you just looking for  
them to reference the header definitions or p6 in general?

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

---

From: "Brian Smith" <[email-masked]>
Date: Wed, 14 Oct 2009 01:51:07 -0500

> them to reference the header definitions or p6 in general?

The definition of "cacheable" is precise enough (see the definition in Part
6), although it is confusing because "cacheable" doesn't imply that a cache
may actually store (aka cache) it; the request and response also have to
meet the requirements in Part 6, Section 2.1 (Response Cacheability).

What I am asking is this: How does a Cache-Control field indicate that an
otherwise-uncacheable response is cacheable? How does an Expires field
indicate that an otherwise-cacheable response is cacheable?

If a 302/303/307 response doesn't contain an Expires header or a
Cache-Control header, then it isn't cacheable. That is clear. But, if the
response contains *any* Expires header, does that make it cacheable? And, if
it contains any Cache-Control header, does that make it cacheable? Or, does
the Cache-Control header have to contain specific values like "public,"
"s-maxage," "must-revalidate", like is specified in Part 7, Section 3.1?
And, if so, what are those specific values? The only cache-control directive
definition that specifically says "cacheable" is "public."

In my implementation, I take the existence of any Cache-Control or Expires
field in the response makes the response cacheable.

Cheers,
Brian

> > What, precisely, must the Cache-Control or Expires header fields
> > contain in order to make a response to a POST, a 302 response,
> > a 303 response, or a 307 response cacheable? This seems to not
> > be specified anywhere in the specification.

---

From: Adrien de Croy <[email-masked]>
Date: Wed, 14 Oct 2009 20:04:57 +1300

> indicate that an otherwise-cacheable response is cacheable?
Expiry means fresh until, which ties in with freshness part of cache 
philosophy, so Expiry header implies cachability (as long as it is in 
the future).

> field in the response makes the response cacheable.
what about Cache-control: no-store, no-cache ?

I think you need to look at what the actual directives are.  As for 
Expiry, it has to be in the future (relative to Date), else it is stale.

IOW I think the response needs to be treated the same way as any other 
response in terms of evaluation of cache-control for cacheability.

Difference might be in treatment of cache validators, since I don't know 
if you can have an ETag or Last-Modified on something that has no entity.

For instance, not every 200 response is cacheable either (which I think 
was asserted earlier in this thread).

Regards

Adrien

-- 
Adrien de Croy - WinGate Proxy Server - http://www.wingate.com

---

From: Mark Nottingham <[email-masked]>
Date: Wed, 14 Oct 2009 18:03:29 +1100

> indicate that an otherwise-cacheable response is cacheable?

By giving it an explicit freshness lifetime, as per p6 2.3.

> response contains *any* Expires header, does that make it cacheable?

You're conflating "can be stored in a cache" with "can be served from  
cache". "cacheable" was used for both in 2616, often in a self- 
conflicting way. What we're currently trying to do is untangle them.

Currently, the interpretation is that status code doesn't figure into  
whether something can be stored (as per the other thread), but it does  
figure into whether something can be served heuristically (i.e.,  
without an assigned explicit freshness lifetime).

> And, if

See above.

---

From: "Brian Smith" <[email-masked]>
Date: Wed, 14 Oct 2009 02:38:38 -0500

> conflicting way. What we're currently trying to do is untangle them.

Gotcha. So, you could just remove all the sentences from Part 2, Section 8
containing the word "cacheable," because Part 6, section 2.3.1.1
(Calculating Heuristic Freshness) already describes the requirements
precisely. Is that correct? That does make sense to me.

I think that 201 and 304 responses cannot be stored in cache, ever, because
they use the ETag header for a different purpose than for supporting
conditional GET, so you cannot validate them with the origin server.

Similarly, does it make sense to cache 405 Method Not Allowed responses to
POST requests, so that they could be returned for a subsequent GET request?
Similarly, POST responses 411 Length Required, 413 Request Entity Too Large,
and 415 Unsupported Media Type responses subsequent GET requests.

Also, 417 Expectation Failed is basically a "hop-by-hop status code" since
it only makes sense when an unsupported value for a hop-by-hop request
header field is provided by the cache to the server.

Finally, note the following statement in Part 2, Section 4: "However,
applications MUST understand the class of any status code, as indicated by
the first digit, and treat any unrecognized response as being equivalent to
the x00 status code of that class, with the exception that an unrecognized
response MUST NOT be cached." Here, I think "MUST NOT be cached" means
specifically "MUST NOT be stored in caches." I think Part 6 should mention
this requirement explicitly.

Regards,
Brian

---

From: Nicolas Alvarez <[email-masked]>
Date: Wed, 14 Oct 2009 14:16:07 -0300

> POST requests, so that they could be returned for a subsequent GET

Does it *ever* make sense to cache the response to a POST request, and
return that cached response for a subsequent GET request?

---

From: Mark Nottingham <[email-masked]>
Date: Thu, 22 Oct 2009 13:52:07 +1100

> header field is provided by the cache to the server.

I think I agree. I believe this can be resolved by further  
constraining what can be stored to things that either:
   a) have explicit freshness information present, or
   b) are allowed to have heuristic freshness information applied

Note that (b) includes such responses even if they don't actually have  
heuristic freshness applied to them; in this manner, a cache can still  
store a 200 response with no Expires or CC: max-age (for example).

Effectively, then, the list of status codes that are cacheable is  
derived from the list of those that allow heuristic freshness to be  
used, with the proviso that other status codes can explicitly state  
their store-ability.

Does this make sense?

If so, there are still two open issues here;

  1) Whether a response with an Expires in the past (for example) can  
be stored (as you brought up), and
  2) Whether caches that don't understand a status code can still  
cache it, if it has explicit freshness available

WRT #1, I think they can, because a cache may want to use that stale  
representation as the basis of revalidation in the future.

> this requirement explicitly.

because there's no reason that a cache has to understand the status  
code, as long as the cache directives are explicit. At any rate, that  
text conflicts with 2616 14.21:

>    The presence of an Expires header field with a date value of some
>    time in the future on a response that otherwise would by default be
>    non-cacheable indicates that the response is cacheable, unless
>    indicated otherwise by a Cache-Control header field (section 14.9).

But we need to discuss this more.

Cheers,

---

From: "Brian Smith" <[email-masked]>
Date: Thu, 22 Oct 2009 00:31:05 -0500

Mark Nottingham wrote:
> > Also, 417 Expectation Failed is basically a "hop-by-hop status code"
> > since it only makes sense when an unsupported value for a hop-by-hop
> > request header field is provided by the cache to the server.
> 

I think Part 6 should be written in a way that is oblivious to any status
codes except 304 and maybe 206. If a cache isn't aware of the method's
cacheability, or it isn't aware of the status code's cacheability, then it
must not cache it; it may only cache responses in accordance with the rules
explicitly stated in each method definition and status code definition. I
would specify the heuristic freshness rules this way too. Part 6 would then
only explicitly mention status codes 304 and maybe 206 (though I'd try to
put all the special handling of 206 into the status code definition).

This way, the definitions of each HTTP-defined method and HTTP-defined
status code would serve as models for people writing specifications for
extension methods/status codes.

> representation as the basis of revalidation in the future.

I agree.

> > applications MUST understand the class of any status code, as
> > indicated by the first digit, and treat any unrecognized response
> > as being equivalent to the x00 status code of that class, with the
> > exception that an unrecognized response MUST NOT be cached." Here,
> > I think "MUST NOT be cached" means specifically "MUST NOT be
> > stored in caches." I think Part 6 should mention
> code, as long as the cache directives are explicit.

To see why that doesn't work, consider four hypothetical extension status
codes:
  
    281, defined to mean the same as 201
    286, defined to mean the same as 206
    384, defined to mean the same as 304
    497, defined to mean the same as 417

A cache that used the same 200/300/400 rule to cache these responses would
erroneously handle all of these responses. Or, put another way, if you
removed the "must understand" requirement I quoted above, then no new status
code could ever have different caching requirements than the default. For
example, no new status code could ever use the ETag header in the same way
201 does, because it would have to use ETag to support validation (note that
you cannot validate a 201 response with the server).

Also, do you want to allow caches to automatically rewrite a "201 Created"
response into a "200 OK" response if the 201 response had
Content-Location=Request-URI and Cache-Control set appropriately? Because it
definitely should not return a cached "201 Created" response (from a PATCH,
POST, or PUT) as-is in response to a subsequent GET.

Cheers,
Brian

---

From: Mark Nottingham <[email-masked]>
Date: Thu, 22 Oct 2009 18:16:20 +1100

> extension methods/status codes.

Makes sense.

>> cache it, if it has explicit freshness availabl

[...]

> you cannot validate a 201 response with the server).

Remember that I said that...

>> this can be resolved by further

281 (for example) would only be cached if it had explicit freshness  
available, or its definition allow heuristic freshness *and* the cache  
understands the status code.

> POST, or PUT) as-is in response to a subsequent GET.

Huh? Ah, I see -- I'm assuming we'd rewrite the requirement about  
being equivalent with the more general X00 status code to refer to  
these rules WRT caching.

---

From: "Brian Smith" <[email-masked]>
Date: Thu, 22 Oct 2009 10:20:46 -0500

Mark Nottingham wrote:
> > Also, do you want to allow caches to automatically rewrite a "201
> > Created" response into a "200 OK" response if the 201 response had
> > Content-Location=Request-URI and Cache-Control set appropriately?
> > Because it definitely should not return a cached "201 Created"
> > response (from a PATCH, POST, or PUT) as-is in response to a
> > subsequent GET.
> 

To clarify: It doesn't make sense for a cache to ever return a cached 201
response, because 201 means that a resource was created on the origin
server, but the origin server didn't even see the request, so nothing was
created. 

It doesn't make sense for a cache to ever return a cached 417 response,
because a 417 response only makes sense when the cache included an Expect
header in its upstream request, and Expect is hop-by-hop.

Those are just two examples. There are quite a few status codes defined
already in the HTTP spec that don't make sense to cache in the default way.
So, I assume that some future status codes will be similar.

If it doesn't make sense to cache a response, then the origin server
shouldn't be including the Cache-Control/Expires headers in its response. I
think that's your position and I totally agree with that. But, it seems
strange to me to say a cache may cache anything with a Cache-Control header
as-is--EXCEPT it must treat 201, 206, 304, 417 (and probably a few more
4xx/5xx errors) specially, but that's it, no new special cases, ever.

Regards,
Brian

---

From: Mark Nottingham <[email-masked]>
Date: Fri, 23 Oct 2009 10:30:01 +1100

On 23/10/2009, at 2:20 AM, Brian Smith wrote:

> think that's your position and I totally agree with that.

Yes.

> But, it seems

Right. If we follow this path, there are roughly three options;

a) Make exceptions for 201, etc. and no more
b) Don't make exceptions for 201, etc. -- i.e., purposefully allow  
servers to shoot themselves in the foot here (without promoting it, of  
course)
c) Allow new status codes to except them, which takes us back to  
caches having to understand status codes to store them.

If we were working from a clean slate, I think (b) is probably the  
right thing to do. However, we're not -- although adopting (b) won't  
make any existing caches non-conformant: one could argue that a 201 or  
a 281 w/ Expires can be cached, thanks to the advice that Expires  
makes a non-cacheable response cacheable.

How do people feel about this? Is (b) workable? If not, (a) or (c), or  
something else?