OkHttp's cache doesn't save multiple response variants for the same target
See original GitHub issueOkHttp’s Cache
seems to replace an existing response entry if another comes from the same target but with different values for request’s Vary
fields. For example consider this test case:
@Test void vary() throws Exception {
var server = new MockWebServer();
server.setDispatcher(new Dispatcher() {
@Override public MockResponse dispatch(RecordedRequest recordedRequest) {
var baseResponse = new MockResponse()
.addHeader("Cache-Control", "max-age=69420")
.addHeader("Vary", "Accept-Encoding");
var body = "ZIP ME!";
var encoding = recordedRequest.getHeader("Accept-Encoding");
if ("gzip".equalsIgnoreCase(encoding)) {
return baseResponse.addHeader("Content-Encoding", "gzip")
.setBody(ZipUtils.gzip(body));
} else if ("deflate".equalsIgnoreCase(encoding)) {
return baseResponse.addHeader("Content-Encoding", "deflate")
.setBody(ZipUtils.deflate(body));
} else {
return baseResponse.setBody(body);
}
}
});
server.start(8080);
var client = new OkHttpClient.Builder()
.cache(new Cache(Files.createTempDirectory("okhttp-cache").toFile(), 10 * 1024))
.build();
var gzipRequest = new Request.Builder()
.url(server.url("/"))
.header("Accept-Encoding", "gzip")
.build();
try (var response = client.newCall(gzipRequest).execute()) {
assertEquals("ZIP ME!", ZipUtils.gunzip(response.body().bytes()));
assertEquals(1, client.cache().networkCount());
assertEquals(0, client.cache().hitCount());
}
// gzip response gets replaced as both requests have same key using by the cache (URL)
var deflateRequest = new Request.Builder()
.url(server.url("/"))
.header("Accept-Encoding", "deflate")
.build();
try (var response = client.newCall(deflateRequest).execute()) {
assertEquals("ZIP ME!", ZipUtils.inflate(response.body().bytes()));
assertEquals(2, client.cache().networkCount());
assertEquals(0, client.cache().hitCount());
}
try (var response = client.newCall(gzipRequest).execute()) {
assertEquals("ZIP ME!", ZipUtils.gunzip(response.body().bytes()));
// Expected: use previously saved response
assertEquals(2, client.cache().networkCount()); // fails: expected 2 but was 3
assertEquals(1, client.cache().hitCount()); // fails: expected 1 but was 0
}
}
I don’t know if this is intentional or not but if I understand correctly, a cache is allowed to have multiple response entries per cache key, each with a secondary key represented by request’s selecting headers values (last paragraph of RFC 7234 sec 2). If this is indeed intentional, it’d be much appreciated to know reasons why.
Thanks in advance & great library!
Issue Analytics
- State:
- Created 3 years ago
- Reactions:2
- Comments:11 (5 by maintainers)
Top Results From Across the Web
Cache - OkHttp - Square Open Source
Caches HTTP and HTTPS responses to the filesystem so they may be reused, saving time and bandwidth. Cache Optimization¶. To measure cache effectiveness,...
Read more >A complete guide to OkHttp - LogRocket Blog
In this guide, you can learn the basics of OkHttp and how to build an imaginary to-do list application for Android with it....
Read more >How to handle RESTful web Services using Retrofit, OkHttp ...
We are going to combine multiple libraries at once to get a working result. I am not going to talk about the native...
Read more >Android Networking I: OkHttp, Volley and Gson - Medium
Reading how many things OkHttp does it's a good way to understand how hard is to do networking: Connection pooling, gziping, caching, recovers...
Read more >Can Retrofit with OKHttp use cache data when offline
1) Create Interceptor: private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() { @Override public Response intercept(Chain chain) ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Its because if we have a variant mismatch we treat it like a stale cache entry. The old variant is not used and the new one will clobber it.
I suspect anyone who hit this probably found it quicker to append a fake “?variant=XML” on the URL than explain the bug and request a fix. It seems like a useful feature if done right, there might even be broader issues here like cache pollution we aren’t handling?