last-modified vs expires precedence - http

I have read through lot of discussions, and found most of the claim saying expires is higher precedence over last-modified, meaning if a response already expired, it will not even send out if-modified-since to server and of course the response code will not be 304.
But my situation is totally weird, I have returned back last-modified in response, and somehow CDN/proxy side add in expires header, which value is same as date response header, I suppose same value in expires and date header will cause the response stale immediately, but in fact, my client browser will still send out request with if-modified-since header, this will cause a 304 response code returned from the server.
I read throught RFC 2616, it doesn't tell much as well. So what happen to this case?

Almost 2 years but find no answer...
I managed find out some reference:
The freshness lifetime is calculated based on several headers. If a
"Cache-control: max-age=N" header is specified, then the freshness
lifetime is equal to N. If this header is not present, which is very
often the case, it is checked if an Expires header is present. If an
Expires header exists, then its value minus the value of the Date
header determines the freshness lifetime. Finally, if neither header
is present, look for a Last-Modified header. If this header is
present, then the cache's freshness lifetime is equal to the value of
the Date header minus the value of the Last-modified header divided by
10.
Although I can't find confirmed precedence in RFC, but I think this MDN quote is quite reliable enough.
It is pretty normal if some browser doesn't implement in this way... So to avoid any issue, the best is to not return these two headers in the response at the same time.

Related

http 304 response combined with cache-control does not seem to work with max-age

On Chrome the cache-control header works when combined with a 304 response.
I have checked this with "cache-control no-store" which makes the Chrome make a regular GET request to the server next time it needs that resource; as expected.
However, "cache-control max-age=42" doesn't work as expected. Instead of not making a GET request to the server the next 42 seconds it makes GET requests with an if-modified-since header even though it shouldn't do that before the 42 seconds has passed.
It's weird that a 200-response with "cache-control max-age=42" work as expected, but a 304-response doesn't.
Any explanation and maybe a way to achieve the same thing?
I have only tested this with Chrome.
When Chrome makes a GET request with an if-modified-since header any max-age in the 304-response is interpreted as a max-age from when the resource was originally returned instead of a max-age from the time of the 304-response.
So in order to make this work the new max-age should be (time-since-original-response + max-age-you-want).
However, the upper limit of max-age is one year.

Which HTTP header takes precedence in the presence of conflicting values?

This question is similar to Are Duplicate HTTP Response Headers acceptable? but goes a step further.
I have observed a webserver in our staging environment that returns the following headers (output has been truncated for clarity):
strict-transport-security: max-age=1
Strict-Transport-Security: max-age=31536000; includeSubDomains
My question is: in the face of conflicting header values, which takes precedence?
Since the RFC states that multiple values must be chainable, this functionality seems undefined as the values are not chainable (since they are conflicting) yet the browser does not return an error.
As it turns out, even though Chrome does not alert me to it, the header above is listed as INVALID and thus no HSTS policy is applied whatsoever.

HTTP header weird field explanation

If you look on the response header of the http://www.yale.edu, there is a field such as
Expires: Sun, 19 Nov 1978 05:00:00 GMT.
What does it stand for?
If you want to look at it yourself, just type in terminal
curl -I http://www.yale.edu
A couple of years back, this was the main way of specifying when assets expires. Expires is simply a basic date-time stamp. It’s fairly useful for old user agents which still roam unchartered territories. It is however important to note that cache-control headers, max-age and s-maxage still take precedence on most modern systems. It’s however good practice to set matching values here for the sake of compatibility. It’s also important to ensure you format the date properly or it might be considered as expired.
taken from here
After that the response is no longer cached. See here
Also worth to look at

Avoiding Content-Length in HEAD response

The Content-Length response header is often expensive to generate for a just HEAD request (e.g. when dealing with dynamically generated resources), but may be essentially "free" after doing the work needed to generate a GET response body.
When it is reasonable to provide a Content-Length (instead of a chunked response) when responding to a GET request, yet unreasonable or slow to calculate the Content-Length for the corresponding HEAD request, is it permissible for the HEAD response to:
Omit the Content-Length header altogether?
Respond with Transfer-Encoding: chunked even though GET response would have a Content-Length?
The relevant W3C specification indicates that a HEAD request "SHOULD" (not "MUST") respond with identical headers; is the cleanliness and, admittedly often minor, total transfer size savings of using Content-Length in the GET response worth violating the aforementioned "SHOULD" in the case of HEAD, or is the only reasonable choice to have both responses send a Transfer-Encoding: chunked header?
Thanks to a tip from #julian-reschke, rfc-7231 indicates that:
The server SHOULD send the same header fields in response to a HEAD request as it would have sent if the request had been a GET, except that the payload header fields (Section 3.3) MAY be omitted.
Per section 3.3 of that same document, the payload header fields consist of:
Content-Length
Content-Range
Trailer
Transfer-Encoding

Does if-match HTTP header require two-phase commits?

I'm trying to design a RESTful web API, so I've been studying rfc2616. I like the idea of using ETags for optimistic concurrency and was trying to use it to make a safe way to add resources without race-conditions. However, I noticed the following two statements in section 14.24:
If the request would, without the If-Match header field, result in anything other than a 2xx or 412 status, then the If-Match header MUST be ignored.
A request intended to update a resource (e.g., a PUT) MAY include an If-Match header field to signal that the request method MUST NOT be applied if the entity corresponding to the If-Match value (a single entity tag) is no longer a representation of that resource.
I'm using a RDBMS and don't know whether a transaction will successfully commit until I try it, so I think the first requirement seems a bit onerous. Consider a case where somebody supplies an If-Match header with mismatched ETags: If the commit would succeed, then I should heed the If-Match header, NOT attempt the commit, and return 412. If the commit would fail, then a request without the If-Match header would have resulted in a non-2XX/412 response, so I MUST ignore the If-Match header, meaning I should attempt the commit.
As far as I can figure out, I have 2 options:
Use 2-phase commits to gain foresight into whether the commit will succeed before attempting it.
Ignore the first requirement above, and return 412 even if ignoring If-Match would have resulted in a non-2XX/412 response. (this is the one I'm leaning towards)
Any other ideas? Am I misinterpreting the specs?
Wouldn't something like "update unless modified" (optimistic locking) work? The entity would need to store a version number or the etag in the database.
run validations that don't require a commit, ignoring the etag, return error if necessary
update entity where id = :the_id and etag = :expected_etag
this returns either 0 or 1 for affected rows
if 0 the resource has seen a concurrent update (or the id is completely wrong, which you could check separately). In this case return 412
commit
if the commit fails, return error as appropriate
Maybe this is somewhat on the theoretical side, but based on my current understanding of the HTTP specification, I would classify the usage of If-Match-like headers practically unusable for all but maybe the safe methods, because of this:
"If the request would, without the If-Match header field, result in anything other than a 2xx or 412 status, then the If-Match header MUST be ignored".
Why? Simply because in most practical cases, it's just impossible to foresee what should happen if the request was carried out.
As an example, who can forsee a IO-level error or some exceptional case occuring in code that must be run?
It'd be more "solvable" if 5xx where added to 2xx and 412.

Resources