playframework / playframework/cachecontrol

CacheControl does not deal with Vary / secondary keys

Open
#37 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Scala
Stars
16
Forks
15
Avg merge
1d 1h
Merged PRs (30d)
24

Description

CacheControl does not have the concept of secondary keys as described in overview of cache operation

If a request target is subject to content negotiation, its cache entry might consist of multiple stored responses, each differentiated by a secondary key for the values of the original request's selecting header fields (Section 4.1).

Secondary keys are calculated from the Vary header as described in Calculating Secondary Keys with Vary.

This is mostly an issue when dealing with resources which use explicit content negotiation, which has failed miserably, but... it is part of the spec.

More details in https://www.smashingmagazine.com/2017/11/understanding-vary-header/

Also see how current browsers handle the fine points of Vary: https://wpt.fyi/results/fetch/http-cache/vary.html?label=stable&aligned

Other hints: https://www.mnot.net/blog/2017/03/16/browser-caching#vary

Discussion of "secondary keys" (a term completely undefined in the RFC itself) https://github.com/tempesta-tech/tempesta/issues/508 -- part of the issue I have with the spec is that it assumes that you are working with a cache which even provides primary and secondary keys. As The Insanity of the Vary Header says:

This isn't really a major problem for developers writing clients and servers, but it's a pain for people trying to write caches. In fact, I haven't found a private cache implementation that actually does this yet.

and

If you think the specification is bad, you should see the implementations.

So even when CacheControl tells you to do the right thing, you're still going to be hosed unless your cache implementation can deal with the ambiguity: the cache entry can be either a single response, or a map of multiple stored responses.

val entry: Entry = cache(primaryCacheKey)
val response: Response = if (entry.containsMultiple) {
  entry.response(secondaryKey)
} else {
  entry.response
}

Do you understand the Vary HTTP header?

Also see https://github.com/httpwg/http-core/issues/110 and https://github.com/httpwg/http-core/issues/28

https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#Varying_responses

https://dzone.com/articles/getting-the-most-out-of-vary-with-fastly

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the RFC 7234 sections on cache operation and calculating secondary keys, then trace the cache lookup and storage model represented by Entry, primaryCacheKey, and secondaryKey in the issue example. The work is complete when Vary responses can be represented and selected correctly without ambiguity; the issue does not name implementation files or tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.