Search code examples
httphttp-headersbrowser-cachehttp-caching

If-Modified-Since overrides If-None-Match in the browser


I have a web server which provides an ETag for a particular url. When the browser performs a request for this url, it provides the http-header "If-None-Match" with the ETag-value contained in the previous response from the server for that url. Now, if I programatically add the request-header "If-Modified-Since" and set it to a either a future or past date (doesn't matter), the browser stops sending the "If-None-Match"-header. I have seen this in both FireFox and Chrome (not tested with any other browser). I can't conclude from the HTTP/1.1 spec that this should be the case. Why does this happen?

Here is a simple code example that will reproduce the scenario. The code assumes that the server responds with an Etag-header.

var request = new XMLHttpRequest();
request.open("GET", someUrl, true);
request.onreadystatechange = function(){};

// This statement makes the browser stop sending the "If-None-Match" header
request.setRequestHeader("If-Modified-Since", "Sat, 29 Oct 1994 19:43:31 GMT"); 

request.send(null);

Solution

  • Now, if I programatically add the request-header "If-Modified-Since" and set it to a either a future or past date (doesn't matter), the browser stops sending the "If-None-Match"-header.

    They shouldn't, if the server provides in both an Etag and Last-Modified header for the given resource:

    HTTP/1.1 clients [...] if both an entity tag and a Last-Modified value have been provided by the origin server, SHOULD use both validators in cache-conditional requests. This allows both HTTP/1.0 and HTTP/1.1 caches to respond appropriately.

    Edit: when calling XmlHttpRequest.open(), the implementation prepares a request using an nsIHttpChannel, using among others the If-Modified-Since and If-None-Match headers if it can find a local cached item.

    Now when you call SetRequestHeader() with either If-(Un)Modified-Since or If-None-Match, it'll clear both headers from the request and sets your value.