5

Since version 59, Firefox has a feature called Race Cache With Network (RCWN). If Firefox detects that the disk is slow, it can decide to start a network requests immediately without waiting for the cache. It is a trade-off: if the network requests wins the race, latency improved; if it the cache wins, network bandwidth has been wasted.

It is a useful feature, but there is one scenario where it is undesirable. Assume a WebExtension needs to update resources in the background (e.g. once per hour). Latency is not important here, although proper caching is crucial as you need to pay for outgoing traffic on the server side.

My question is how to disable RCWN on a request level. How can you create a request (through fetch or XMLHttpRequest) that will always check the cache first and only then issue a network request. In other words, never race and never bypass the cache.

I know that the feature can be turned off through configurations (network.http.rcwn.enabled), but that is not a solution. First, you would need to convince every user to flip that preference. Second, RCWN is a useful feature and it provides value during normal surfing where latency is important. Forcing users to disable it would lead to a suboptimal browsing experience.

There is little documentation on RCWN expects these slides, but I found its implementation in the Firefox source code:

nsresult nsHttpChannel::OpenCacheEntryInternal(...) {
  ...
  if (sRCWNEnabled && maybeRCWN && !mApplicationCacheForWrite) {
    bool hasAltData = false;
    uint32_t sizeInKb = 0;
    rv = cacheStorage->GetCacheIndexEntryAttrs(openURI, extension, &hasAltData,
                                               &sizeInKb);

    // We will attempt to race the network vs the cache if we've found
    // this entry in the cache index, and it has appropriate attributes
    // (doesn't have alt-data, and has a small size)
    if (NS_SUCCEEDED(rv) && !hasAltData &&
        sizeInKb < sRCWNSmallResourceSizeKB) {
      MaybeRaceCacheWithNetwork();
    }
  }
  ...
}

I tried to understand the concept of "alt-data", but could not find any sources. To the best of my knowledge, it stands for alternative data. Could that be used (either by the server or through the client request) to force the cached data to be marked as alt-data, so racing will not occur?

One other idea that I had: in a fetch request, clients can set Cache-Control: only-if-cached, but that changes the semantic. It should stop races, but if there is no hit, it will return a stale result and not ask the server. Maybe that could be used to first try such a request and only then do a real network request. Not very elegant though. Is there some better solution to this problem?


Notes: to get more information, Firefox allows to introspect the RCWN through about:networking#rcwn, and the cache through about:cache. If you check the RCWN, you can see that races are not too rare, even if you have an SSD. In the network monitor, raced requests will be marked in the transferred column, for example, as 100.86 KB (raced).

Philipp Claßen
  • 41,306
  • 31
  • 146
  • 239
  • Have you tried `Cache-Control: immutable`. Will it suit your needs? – x00 Feb 21 '20 at 19:09
  • And also, there is `ETag` header. I imagine it's usage still leads to races, but requests will not waste too much of bandwidth. https://www.keycdn.com/blog/http-cache-headers – x00 Feb 21 '20 at 19:30
  • @x00 "immutable" changes the semantics if you expect the resources to occasionally change. It is true that in some scenarios, skipping requests completely for a certain time period could work (depends on how quickly you need to detect new changes). Regarding ETags, I'm aware and I see the practical side: conditional requests are small, so the overhead of the races is significantly reduced. Still, I'm curious whether there is a way to prevent them as well. – Philipp Claßen Feb 21 '20 at 20:38
  • 1
    A vague info about `alt-data`: https://bugzilla.mozilla.org/show_bug.cgi?id=1487113 I haven't made further research, but I guess that `alt-data` is not what you can use. Looks like `alt-data` is there to memoize heavy resource transformations...or something, and if there is such a memoized result in cache, then FF will not initiate RCWN, because it would still need to read `alt-data` from the disk anyway. – x00 Feb 22 '20 at 14:25

0 Answers0