Can a user agent set a max-age greater than zero in its request?

1.2k views Asked by At

I have a doubt about max-age behaviour after reading the Http Cache rfc.

Scenario:

User agent

GET /foo

Origin Server Response header

cache-control: max-age=120

Server tells user agent that the resource requested should be revalidated after 2 minutes.

After 1 minute and few seconds, User agent makes another request, specifying a max-age of 1 minute:

User agent

cache-control: max-age=60
GET /foo

From what I understand, this request should bypass the user agent cache.
Why?
Although the Origin Server told the client that the resource should be cached for 2 minutes, User agent needs a resource that is at most 1 minute old (max-age = 60).
After 1 minute and few seconds from the first GET, that resource is not valid (from the User Agent point of view) and a request should go straight to the origin server (Or any other cache layers).

Am I right? Is it possible to specify, from User Agent, a max-age greater than zero? Is it supported/honored by the common browsers?

Where I work, we have a .NET custom caching mechanism that works like this; clients can specify a max-age when they need a resource from the cache that is "AT MOST" X seconds old.

2

There are 2 answers

2
Rei On BEST ANSWER

There is no need for any doubt. RFC7234 Section 5.2.1.1 includes an example max-age=5 which is of course greater than zero. The definition is also clear (emphasis mine):

The "max-age" request directive indicates that the client is unwilling to accept a response whose age is greater than the specified number of seconds.

"The specified number of seconds" can be any non-negative integer (defined in Section 1.2.1). So the answer is a definite yes.

Additionally, the definition I quoted above also explains the cache behavior in your scenario. But before I get to that, I should correct the following:

Server tells user agent that the resource requested should be revalidated after 2 minutes.

Incorrect.

The max-age=120 directive means that the server tells all caches, not the user agent, that the response must be considered stale after 2 minutes. From Section 5.2.2.8 (emphasis mine):

The "max-age" response directive indicates that the response is to be considered stale after its age is greater than the specified number of seconds.

As you can see, there is no revalidation requirement. If there are no requests to the same resource until 10 minutes later, there won't be any revalidation until 10 minutes later.

Also, from Section 5.2 (emphasis mine):

The "Cache-Control" header field is used to specify directives for caches along the request/response chain.

Just caches, not user agent.

Each participant in the request/response chain receives the same response with the same Cache-Control header, but the intended recipients of the Cache-Control header are just caches. Remember, just because you receive it, doesn't mean it is for you.

For the rest of your scenario, your assessment is correct. I'll quote it here:

After 1 minute and few seconds, User agent makes another request, specifying a max-age of 1 minute:

...

From what I understand, this request should bypass the user agent cache. Why?

Because at the time of the request, the age of the stored response is more than 60 seconds. It should be obvious that if the age of a stored response is, say, 65 seconds, it cannot be used to satisfy a request with a max-age=60 directive. Thus, the cache simply obeys the directive it receives.

In fact, any standards compliant HTTP cache whether integrated in a browser or separate is required to obey the directive it receives, as stated in Section 5.2 (uppercase emphasis from source, not mine):

A cache MUST obey the requirements of the Cache-Control directives defined in this section.

Based on what you described, the custom caching mechanism you have at work seems to be standards compliant. So, my complements to the developers, particularly if by "custom" you mean "developed in house".

0
nbari On

From the RFC2616 max-age

  When an intermediate cache is forced, by means of a max-age=0
  directive, to revalidate its own cache entry, and the client has
  supplied its own validator in the request, the supplied validator
  might differ from the validator currently stored with the cache
  entry. In this case, the cache MAY use either validator in making
  its own request without affecting semantic transparency.

  However, the choice of validator might affect performance. The
  best approach is for the intermediate cache to use its own
  validator when making its request. If the server replies with 304
  (Not Modified), then the cache can return its now validated copy
  to the client with a 200 (OK) response. If the server replies with
  a new entity and cache validator, however, the intermediate cache
  can compare the returned validator with the one provided in the
  client's request, using the strong comparison function. If the
  client's validator is equal to the origin server's, then the
  intermediate cache simply returns 304 (Not Modified). Otherwise,
  it returns the new entity with a 200 (OK) response.

  If a request includes the no-cache directive, it SHOULD NOT
  include min-fresh, max-stale, or max-age.

From the last lines of the RFC:

If a request includes the no-cache directive, it SHOULD NOT include min-fresh, max-stale, or max-age.

From 13.2.6 Disambiguating Multiple Responses section

When a client tries to revalidate a cache entry,
and the response it receives contains a Date header that
appears to be older than the one for the existing entry, 
then the client SHOULD repeat the request 
unconditionally, and include

    Cache-Control: max-age=0

to force any intermediate caches to validate their copies directly with the origin server, or

    Cache-Control: no-cache

to force any intermediate caches to obtain a new copy from the origin server.

If the Date values are equal, then the client MAY use either response
(or MAY, if it is being extremely prudent, request a new response).
Servers MUST NOT depend on clients being able to choose 
deterministically between responses generated during the same
second, if their expiration times overlap.

My understanding is that from the client side (user agent) max-age=0 can be used as a mechanism for using the latest stored version, in contrast to no-cache, that will refetch the resource.

curl -I -H 'Cache-Control: no-cache' http://example.com 

Therefore if using max-age with a value bigger than zero instead it should use the stored version matching the difference between the received Date in the headers an the value defined in the max-age.

Not sure If I am righ but is as I undestandit.

Complementing with similar question: What's the difference between Cache-Control: max-age=0 and no-cache?