1e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller/* 2e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Copyright (C) 2011 The Android Open Source Project 3e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 4e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 5e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * you may not use this file except in compliance with the License. 6e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * You may obtain a copy of the License at 7e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 8e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 9e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 10e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Unless required by applicable law or agreed to in writing, software 11e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 12e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * See the License for the specific language governing permissions and 14e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * limitations under the License. 15e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 16e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 17e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpackage com.squareup.okhttp; 18e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 19e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.internal.Internal; 20e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.internal.SslContextBuilder; 21e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.internal.Util; 2271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport com.squareup.okhttp.internal.io.FileSystem; 2371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport com.squareup.okhttp.internal.io.InMemoryFileSystem; 24e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.mockwebserver.MockResponse; 25e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.mockwebserver.MockWebServer; 26e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.mockwebserver.RecordedRequest; 27e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.io.File; 28e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.io.IOException; 29e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.net.CookieHandler; 30e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.net.CookieManager; 31e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.net.HttpCookie; 32e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.net.HttpURLConnection; 33e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.net.ResponseCache; 34e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.security.Principal; 35e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.security.cert.Certificate; 36e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.text.DateFormat; 37e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.text.SimpleDateFormat; 38e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.ArrayList; 39e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Arrays; 40e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Date; 41e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Iterator; 42e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.List; 43e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Locale; 44e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.NoSuchElementException; 45e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.TimeZone; 46e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.concurrent.TimeUnit; 47e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.concurrent.atomic.AtomicReference; 483be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport javax.net.ssl.HostnameVerifier; 493be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport javax.net.ssl.SSLContext; 503be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport javax.net.ssl.SSLSession; 513be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport okio.Buffer; 523be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport okio.BufferedSink; 533be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport okio.BufferedSource; 543be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport okio.GzipSink; 553be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport okio.Okio; 563be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport org.junit.After; 573be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport org.junit.Before; 583be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport org.junit.Rule; 593be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fullerimport org.junit.Test; 60e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 61e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static com.squareup.okhttp.mockwebserver.SocketPolicy.DISCONNECT_AT_END; 62e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertEquals; 63e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertFalse; 64e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertNotNull; 65e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertNull; 66e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertTrue; 67e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.fail; 68e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 69e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller/** Test caching with {@link OkUrlFactory}. */ 70e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpublic final class CacheTest { 71e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private static final HostnameVerifier NULL_HOSTNAME_VERIFIER = new HostnameVerifier() { 72e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override public boolean verify(String s, SSLSession sslSession) { 73e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return true; 74e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 75e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller }; 76e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 7771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller @Rule public MockWebServer server = new MockWebServer(); 7871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller @Rule public MockWebServer server2 = new MockWebServer(); 79e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 8071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller private final SSLContext sslContext = SslContextBuilder.localhost(); 8171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller private final FileSystem fileSystem = new InMemoryFileSystem(); 82e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private final OkHttpClient client = new OkHttpClient(); 83e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private Cache cache; 84e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private final CookieManager cookieManager = new CookieManager(); 85e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 86e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Before public void setUp() throws Exception { 87e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.setProtocolNegotiationEnabled(false); 8871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem); 89e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setCache(cache); 90e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller CookieHandler.setDefault(cookieManager); 91e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 92e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 93e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @After public void tearDown() throws Exception { 94e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller ResponseCache.setDefault(null); 95e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller CookieHandler.setDefault(null); 96e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 97e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 98e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 99e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Test that response caching is consistent with the RI and the spec. 100e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 102e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseCachingByResponseCode() throws Exception { 103e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Test each documented HTTP/1.1 code, plus the first unused value in each range. 104e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 105e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 106e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // We can't test 100 because it's not really a response. 107e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // assertCached(false, 100); 108e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 101); 109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 102); 110e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 200); 111e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 201); 112e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 202); 113e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 203); 114e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 204); 115e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 205); 116e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 206); //Electing to not cache partial responses 117e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 207); 118e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 300); 119e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 301); 120e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 302); 121e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 303); 122e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 304); 123e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 305); 124e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 306); 125e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 307); 126e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 308); 127e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 400); 128e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 401); 129e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 402); 130e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 403); 131e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 404); 132e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 405); 133e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 406); 134e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 408); 135e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 409); 136e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // the HTTP spec permits caching 410s, but the RI doesn't. 137e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 410); 138e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 411); 139e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 412); 140e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 413); 141e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 414); 142e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 415); 143e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 416); 144e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 417); 145e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 418); 146e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 147e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 500); 148e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 501); 149e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 502); 150e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 503); 151e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 504); 152e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 505); 153e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 506); 154e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 155e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 156e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertCached(boolean shouldPut, int responseCode) throws Exception { 157e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server = new MockWebServer(); 158e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller MockResponse mockResponse = new MockResponse() 159e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 160e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 161e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(responseCode) 162e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("ABCDE") 163e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("WWW-Authenticate: challenge"); 164e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) { 165e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller mockResponse.addHeader("Proxy-Authenticate: Basic realm=\"protected area\""); 166e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { 167e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller mockResponse.addHeader("WWW-Authenticate: Basic realm=\"protected area\""); 16871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller } else if (responseCode == HttpURLConnection.HTTP_NO_CONTENT 16971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller || responseCode == HttpURLConnection.HTTP_RESET) { 17071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller mockResponse.setBody(""); // We forbid bodies for 204 and 205. 171e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 172e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(mockResponse); 173e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.start(); 174e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 175e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 17671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 177e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 178e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 179e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(responseCode, response.code()); 180e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 181e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Exhaust the content stream. 182e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.body().string(); 183e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 184e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response cached = cache.get(request); 185e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller if (shouldPut) { 186e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotNull(Integer.toString(responseCode), cached); 187e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cached.body().close(); 188e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } else { 189e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(Integer.toString(responseCode), cached); 190e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 191e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 192e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 193e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 194e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseCachingAndInputStreamSkipWithFixedLength() throws IOException { 195e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testResponseCaching(TransferKind.FIXED_LENGTH); 196e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 197e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 198e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 199e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testResponseCaching(TransferKind.CHUNKED); 200e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 201e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 202e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 203e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testResponseCaching(TransferKind.END_OF_STREAM); 204e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 205e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 206e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 207e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Skipping bytes in the input stream caused ResponseCache corruption. 208e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * http://code.google.com/p/android/issues/detail?id=8175 209e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 210e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void testResponseCaching(TransferKind transferKind) throws IOException { 211e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller MockResponse mockResponse = new MockResponse() 212e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 213e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 214e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setStatus("HTTP/1.1 200 Fantastic"); 215e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller transferKind.setBody(mockResponse, "I love puppies but hate spiders", 1); 216e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(mockResponse); 217e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 218e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Make sure that calling skip() doesn't omit bytes from the cache. 21971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Request request = new Request.Builder().url(server.url("/")).build(); 220e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request).execute(); 221e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 222e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSource in1 = response1.body().source(); 223e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("I love ", in1.readUtf8("I love ".length())); 224e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller in1.skip("puppies but hate ".length()); 225e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("spiders", in1.readUtf8("spiders".length())); 226e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(in1.exhausted()); 227e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller in1.close(); 228e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteSuccessCount()); 229e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getWriteAbortCount()); 230e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 231e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request).execute(); 232e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSource in2 = response2.body().source(); 233e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("I love puppies but hate spiders", 234e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller in2.readUtf8("I love puppies but hate spiders".length())); 235e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(200, response2.code()); 236e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("Fantastic", response2.message()); 237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 238e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(in2.exhausted()); 239e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller in2.close(); 240e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteSuccessCount()); 241e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getWriteAbortCount()); 242e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getRequestCount()); 243e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getHitCount()); 244e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 245e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 246e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void secureResponseCaching() throws IOException { 247e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.useHttps(sslContext.getSocketFactory(), false); 248e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 249e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 250e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 251e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("ABC")); 252e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 253e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setSslSocketFactory(sslContext.getSocketFactory()); 254e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 255e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 25671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Request request = new Request.Builder().url(server.url("/")).build(); 257e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request).execute(); 258e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSource in = response1.body().source(); 259e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", in.readUtf8()); 260e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 261e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 262e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String suite = response1.handshake().cipherSuite(); 263e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller List<Certificate> localCerts = response1.handshake().localCertificates(); 264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller List<Certificate> serverCerts = response1.handshake().peerCertificates(); 265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Principal peerPrincipal = response1.handshake().peerPrincipal(); 266e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Principal localPrincipal = response1.handshake().localPrincipal(); 267e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 268e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request).execute(); // Cached! 269e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response2.body().source().readUtf8()); 270e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 271e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getRequestCount()); 272e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 273e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getHitCount()); 274e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 275e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(suite, response2.handshake().cipherSuite()); 276e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(localCerts, response2.handshake().localCertificates()); 277e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(serverCerts, response2.handshake().peerCertificates()); 278e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(peerPrincipal, response2.handshake().peerPrincipal()); 279e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(localPrincipal, response2.handshake().localPrincipal()); 280e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 281e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 282e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseCachingAndRedirects() throws Exception { 283e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 284e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 285e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 286e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 287e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Location: /foo")); 288e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 289e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 290e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 291e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("ABC")); 292e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 293e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("DEF")); 294e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 29571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Request request = new Request.Builder().url(server.url("/")).build(); 296e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request).execute(); 297e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response1.body().string()); 298e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 299e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request).execute(); // Cached! 300e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response2.body().string()); 301e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 302e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects 303e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getNetworkCount()); 304e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getHitCount()); 305e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 306e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 307e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void redirectToCachedResult() throws Exception { 308e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 309e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 310e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("ABC")); 311e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 312e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 313e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Location: /foo")); 314e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 315e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("DEF")); 316e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 31771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Request request1 = new Request.Builder().url(server.url("/foo")).build(); 318e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request1).execute(); 319e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response1.body().string()); 320e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest recordedRequest1 = server.takeRequest(); 321e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("GET /foo HTTP/1.1", recordedRequest1.getRequestLine()); 322e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, recordedRequest1.getSequenceNumber()); 323e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 32471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Request request2 = new Request.Builder().url(server.url("/bar")).build(); 325e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request2).execute(); 326e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response2.body().string()); 327e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest recordedRequest2 = server.takeRequest(); 328e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("GET /bar HTTP/1.1", recordedRequest2.getRequestLine()); 329e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, recordedRequest2.getSequenceNumber()); 330e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 331e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // an unrelated request should reuse the pooled connection 33271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Request request3 = new Request.Builder().url(server.url("/baz")).build(); 333e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response3 = client.newCall(request3).execute(); 334e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("DEF", response3.body().string()); 335e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest recordedRequest3 = server.takeRequest(); 336e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("GET /baz HTTP/1.1", recordedRequest3.getRequestLine()); 337e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, recordedRequest3.getSequenceNumber()); 338e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 339e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 340e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void secureResponseCachingAndRedirects() throws IOException { 341e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.useHttps(sslContext.getSocketFactory(), false); 342e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 343e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 344e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 345e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 346e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Location: /foo")); 347e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 348e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 349e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 350e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("ABC")); 351e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 352e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("DEF")); 353e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 354e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setSslSocketFactory(sslContext.getSocketFactory()); 355e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 356e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 35771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/")); 358e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response1.body().string()); 359e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotNull(response1.handshake().cipherSuite()); 360e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 361e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Cached! 36271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/")); 363e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response2.body().string()); 364e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotNull(response2.handshake().cipherSuite()); 365e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 366e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 367e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getHitCount()); 368e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(response1.handshake().cipherSuite(), response2.handshake().cipherSuite()); 369e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 370e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 371e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 372e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * We've had bugs where caching and cross-protocol redirects yield class 373e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * cast exceptions internal to the cache because we incorrectly assumed that 374e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * HttpsURLConnection was always HTTPS and HttpURLConnection was always HTTP; 375e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * in practice redirects mean that each can do either. 376e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 377e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * https://github.com/square/okhttp/issues/214 378e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 379e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void secureResponseCachingAndProtocolRedirects() throws IOException { 380e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server2.useHttps(sslContext.getSocketFactory(), false); 381e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server2.enqueue(new MockResponse() 382e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 383e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 384e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("ABC")); 385e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server2.enqueue(new MockResponse() 386e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("DEF")); 387e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 388e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 389e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 390e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 391e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 39271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .addHeader("Location: " + server2.url("/"))); 393e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 394e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setSslSocketFactory(sslContext.getSocketFactory()); 395e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 396e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 39771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/")); 398e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response1.body().string()); 399e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 400e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Cached! 40171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/")); 402e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", response2.body().string()); 403e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 404e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 405e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getHitCount()); 406e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 407e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 408e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void foundCachedWithExpiresHeader() throws Exception { 409e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller temporaryRedirectCachedWithCachingHeader(302, "Expires", formatDate(1, TimeUnit.HOURS)); 410e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 411e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 412e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void foundCachedWithCacheControlHeader() throws Exception { 413e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller temporaryRedirectCachedWithCachingHeader(302, "Cache-Control", "max-age=60"); 414e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 415e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 416e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void temporaryRedirectCachedWithExpiresHeader() throws Exception { 417e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller temporaryRedirectCachedWithCachingHeader(307, "Expires", formatDate(1, TimeUnit.HOURS)); 418e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 419e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 420e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void temporaryRedirectCachedWithCacheControlHeader() throws Exception { 421e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller temporaryRedirectCachedWithCachingHeader(307, "Cache-Control", "max-age=60"); 422e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 423e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 424e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void foundNotCachedWithoutCacheHeader() throws Exception { 425e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller temporaryRedirectNotCachedWithoutCachingHeader(302); 426e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 427e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 428e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void temporaryRedirectNotCachedWithoutCacheHeader() throws Exception { 429e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller temporaryRedirectNotCachedWithoutCachingHeader(307); 430e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 431e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 432e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void temporaryRedirectCachedWithCachingHeader( 433e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller int responseCode, String headerName, String headerValue) throws Exception { 434e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 435e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(responseCode) 436e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader(headerName, headerValue) 437e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Location", "/a")); 438e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 439e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader(headerName, headerValue) 440e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 441e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 442e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("b")); 443e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 444e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("c")); 445e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 44671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 447e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 448e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 449e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 450e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 451e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void temporaryRedirectNotCachedWithoutCachingHeader(int responseCode) throws Exception { 452e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 453e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(responseCode) 454e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Location", "/a")); 455e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 456e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 457e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 458e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("b")); 459e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 46071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 461e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 462e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("b", get(url).body().string()); 463e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 464e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 465e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void serverDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 466e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 467e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 468e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 469e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void serverDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 470e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testServerPrematureDisconnect(TransferKind.CHUNKED); 471e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 472e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 473e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void serverDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 474e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Intentionally empty. This case doesn't make sense because there's no 475e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // such thing as a premature disconnect when the disconnect itself 476e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // indicates the end of the data stream. 477e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 478e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 479e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 480e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller MockResponse mockResponse = new MockResponse(); 481e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller transferKind.setBody(mockResponse, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 482e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(truncateViolently(mockResponse, 16)); 483e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 484e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("Request #2")); 485e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 48671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller BufferedSource bodySource = get(server.url("/")).body().source(); 487e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCDE", bodySource.readUtf8Line()); 488e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 489e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller bodySource.readUtf8Line(); 490e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("This implementation silently ignored a truncated HTTP body."); 491e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IOException expected) { 492e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } finally { 493e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller bodySource.close(); 494e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 495e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 496e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteAbortCount()); 497e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getWriteSuccessCount()); 49871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response = get(server.url("/")); 499e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("Request #2", response.body().string()); 500e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteAbortCount()); 501e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteSuccessCount()); 502e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 503e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 504e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void clientPrematureDisconnectWithContentLengthHeader() throws IOException { 505e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 506e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 507e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 508e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void clientPrematureDisconnectWithChunkedEncoding() throws IOException { 509e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testClientPrematureDisconnect(TransferKind.CHUNKED); 510e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 511e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 512e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void clientPrematureDisconnectWithNoLengthHeaders() throws IOException { 513e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 514e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 515e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 516e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 517e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Setting a low transfer speed ensures that stream discarding will time out. 518e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller MockResponse mockResponse = new MockResponse() 519e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .throttleBody(6, 1, TimeUnit.SECONDS); 520e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller transferKind.setBody(mockResponse, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 521e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(mockResponse); 522e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 523e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("Request #2")); 524e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 52571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/")); 526e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSource in = response1.body().source(); 527e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCDE", in.readUtf8(5)); 528e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller in.close(); 529e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 530e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller in.readByte(); 531e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("Expected an IllegalStateException because the source is closed."); 532e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 533e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 534e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 535e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteAbortCount()); 536e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getWriteSuccessCount()); 53771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/")); 538e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("Request #2", response2.body().string()); 539e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteAbortCount()); 540e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getWriteSuccessCount()); 541e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 542e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 543e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void defaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 544e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // last modified: 105 seconds ago 545e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // served: 5 seconds ago 546e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // default lifetime: (105 - 5) / 10 = 10 seconds 547e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // expires: 10 seconds from served date = 5 seconds from now 548e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 549e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 550e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 551e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 552e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 55371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 554e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = get(url); 555e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 556e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 557e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = get(url); 558e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 559e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(response2.header("Warning")); 560e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 561e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 562e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void defaultExpirationDateConditionallyCached() throws Exception { 563e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // last modified: 115 seconds ago 564e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // served: 15 seconds ago 565e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // default lifetime: (115 - 15) / 10 = 10 seconds 566e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // expires: 10 seconds from served date = 5 seconds ago 567e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 568e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 569e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedDate) 570e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 571e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 572e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 573e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 574e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void defaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 575e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // last modified: 105 days ago 576e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // served: 5 days ago 577e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // default lifetime: (105 - 5) / 10 = 10 days 578e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // expires: 10 days from served date = 5 days from now 579e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 580e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 581e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 582e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 583e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 58471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 58571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response = get(server.url("/")); 586e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 587e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("113 HttpURLConnection \"Heuristic expiration\"", response.header("Warning")); 588e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 589e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 590e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void noDefaultExpirationForUrlsWithQueryString() throws Exception { 591e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 592e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 593e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 594e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 595e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 596e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 597e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 59871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/").newBuilder().addQueryParameter("foo", "bar").build(); 599e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 600e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", get(url).body().string()); 601e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 602e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 603e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void expirationDateInThePastWithLastModifiedHeader() throws Exception { 604e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 605e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 606e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedDate) 607e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 608e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 609e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 610e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 611e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void expirationDateInThePastWithNoLastModifiedHeader() throws Exception { 612e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 613e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 614e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 615e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 616e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void expirationDateInTheFuture() throws Exception { 617e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 618e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 619e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 620e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 621e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgePreferredWithMaxAgeAndExpires() throws Exception { 622e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 623e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 624e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 625e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 626e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 627e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 628e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 629e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 630e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 631e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 632e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedDate) 633e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 634e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 635e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 636e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 637e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 638e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Chrome interprets max-age relative to the local clock. Both our cache 639e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // and Firefox both use the earlier of the local and server's clock. 640e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 641e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 642e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 643e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 644e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 645e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgeInTheFutureWithDateHeader() throws Exception { 646e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 647e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 648e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 649e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 650e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 651e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgeInTheFutureWithNoDateHeader() throws Exception { 652e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 653e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 654e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 655e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 656e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgeWithLastModifiedButNoServedDate() throws Exception { 657e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 658e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 659e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 660e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 661e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 662e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 663e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 664e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 665e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 666e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 667e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 668e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 669e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgePreferredOverLowerSharedMaxAge() throws Exception { 670e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 671e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 672e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: s-maxage=60") 673e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=180")); 674e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 675e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 676e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void maxAgePreferredOverHigherMaxAge() throws Exception { 677e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 678e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 679e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: s-maxage=180") 680e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 681e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 682e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 683e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMethodOptionsIsNotCached() throws Exception { 684e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testRequestMethod("OPTIONS", false); 685e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 686e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 687e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMethodGetIsCached() throws Exception { 688e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testRequestMethod("GET", true); 689e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 690e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 691e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMethodHeadIsNotCached() throws Exception { 692e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // We could support this but choose not to for implementation simplicity 693e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testRequestMethod("HEAD", false); 694e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 695e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 696e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMethodPostIsNotCached() throws Exception { 697e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // We could support this but choose not to for implementation simplicity 698e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testRequestMethod("POST", false); 699e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 700e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 701e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMethodPutIsNotCached() throws Exception { 702e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testRequestMethod("PUT", false); 703e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 704e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 705e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMethodDeleteIsNotCached() throws Exception { 706e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testRequestMethod("DELETE", false); 707e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 708e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 709e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMethodTraceIsNotCached() throws Exception { 710e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testRequestMethod("TRACE", false); 711e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 712e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 713e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 714e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 1. seed the cache (potentially) 715e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 2. expect a cache hit or miss 716e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 717e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 718e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("X-Response-ID: 1")); 719e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 720e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("X-Response-ID: 2")); 721e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 72271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 723e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 724e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 725e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 726e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .method(requestMethod, requestBodyOrNull(requestMethod)) 727e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 728e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request).execute(); 729e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response1.body().close(); 730e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("1", response1.header("X-Response-ID")); 731e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 732e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = get(url); 733e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response2.body().close(); 734e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller if (expectCached) { 735e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("1", response2.header("X-Response-ID")); 736e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } else { 737e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("2", response2.header("X-Response-ID")); 738e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 739e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 740e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 741e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private RequestBody requestBodyOrNull(String requestMethod) { 742e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return (requestMethod.equals("POST") || requestMethod.equals("PUT")) 743e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller ? RequestBody.create(MediaType.parse("text/plain"), "foo") 744e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller : null; 745e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 746e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 747e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void postInvalidatesCache() throws Exception { 748e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testMethodInvalidates("POST"); 749e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 750e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 751e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void putInvalidatesCache() throws Exception { 752e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testMethodInvalidates("PUT"); 753e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 754e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 755e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void deleteMethodInvalidatesCache() throws Exception { 756e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller testMethodInvalidates("DELETE"); 757e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 758e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 759e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void testMethodInvalidates(String requestMethod) throws Exception { 760e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 1. seed the cache 761e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 2. invalidate it 762e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 3. expect a cache miss 763e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 764e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 765e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 766e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 767e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 768e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 769e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("C")); 770e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 77171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 772e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 773e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 774e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 775e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 776e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 777e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .method(requestMethod, requestBodyOrNull(requestMethod)) 778e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 779e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response invalidate = client.newCall(request).execute(); 780e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", invalidate.body().string()); 781e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 782e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("C", get(url).body().string()); 783e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 784e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 785e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void postInvalidatesCacheWithUncacheableResponse() throws Exception { 786e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 1. seed the cache 787e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 2. invalidate it with uncacheable response 788e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 3. expect a cache miss 789e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 790e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 791e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 792e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 793e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B") 794e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(500)); 795e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 796e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("C")); 797e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 79871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 799e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 800e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 801e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 802e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 803e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 804e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .method("POST", requestBodyOrNull("POST")) 805e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 806e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response invalidate = client.newCall(request).execute(); 807e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", invalidate.body().string()); 808e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 809e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("C", get(url).body().string()); 810e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 811e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 812e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void etag() throws Exception { 813e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 814e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("ETag: v1")); 815e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("v1", conditionalRequest.getHeader("If-None-Match")); 816e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 817e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 8183be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fuller /** If both If-Modified-Since and If-None-Match conditions apply, send only If-None-Match. */ 819e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void etagAndExpirationDateInThePast() throws Exception { 820e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 821e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 822e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("ETag: v1") 823e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedDate) 824e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 825e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("v1", conditionalRequest.getHeader("If-None-Match")); 8263be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fuller assertNull(conditionalRequest.getHeader("If-Modified-Since")); 827e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 828e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 829e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void etagAndExpirationDateInTheFuture() throws Exception { 830e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFullyCached(new MockResponse() 831e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("ETag: v1") 832e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 833e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 834e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 835e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 836e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cacheControlNoCache() throws Exception { 837e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 838e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: no-cache")); 839e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 840e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 841e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 842e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 843e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 844e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedDate) 845e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 846e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: no-cache")); 847e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 848e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 849e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 850e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void pragmaNoCache() throws Exception { 851e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 852e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Pragma: no-cache")); 853e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 854e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 855e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void pragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 856e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 857e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 858e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedDate) 859e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 860e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Pragma: no-cache")); 861e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 862e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 863e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 864e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cacheControlNoStore() throws Exception { 865e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 866e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: no-store")); 867e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 868e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 869e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 870e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 871e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 872e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 873e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: no-store")); 874e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 875e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 876e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void partialRangeResponsesDoNotCorruptCache() throws Exception { 877e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 1. request a range 878e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // 2. request a full document, expecting a cache miss 879e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 880e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("AA") 881e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 882e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 883e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Range: bytes 1000-1001/2000")); 884e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 885e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("BB")); 886e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 88771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 888e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 889e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 890e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 891e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Range", "bytes=1000-1001") 892e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 893e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response range = client.newCall(request).execute(); 894e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("AA", range.body().string()); 895e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 896e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("BB", get(url).body().string()); 897e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 898e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 899e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void serverReturnsDocumentOlderThanCache() throws Exception { 900e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 901e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 902e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 903e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 904e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 905e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B") 906e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 907e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 90871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 909e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 910e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 911e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 912e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 913e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 914e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void clientSideNoStore() throws Exception { 915e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 916e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 917e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 918e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 919e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 920e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 921e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 922e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request1 = new Request.Builder() 92371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 924e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .cacheControl(new CacheControl.Builder().noStore().build()) 925e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 926e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request1).execute(); 927e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 928e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 929e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request2 = new Request.Builder() 93071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 931e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 932e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request2).execute(); 933e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response2.body().string()); 934e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 935e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 936e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void nonIdentityEncodingAndConditionalCache() throws Exception { 937e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNonIdentityEncodingCached(new MockResponse() 938e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 939e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 940e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 941e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 942e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void nonIdentityEncodingAndFullCache() throws Exception { 943e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNonIdentityEncodingCached(new MockResponse() 944e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 945e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 946e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 947e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 948e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 949e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(response 950e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody(gzip("ABCABCABC")) 951e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Encoding: gzip")); 952e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 953e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 954e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 955e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 956e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 957e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // At least three request/response pairs are required because after the first request is cached 958e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // a different execution path might be taken. Thus modifications to the cache applied during 959e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // the second request might not be visible until another request is performed. 96071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("ABCABCABC", get(server.url("/")).body().string()); 96171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("ABCABCABC", get(server.url("/")).body().string()); 96271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("ABCABCABC", get(server.url("/")).body().string()); 963e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 964e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 965e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void notModifiedSpecifiesEncoding() throws Exception { 966e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 967e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody(gzip("ABCABCABC")) 968e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Encoding: gzip") 969e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 970e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 971e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 972e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED) 973e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Encoding: gzip")); 974e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 975e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("DEFDEFDEF")); 976e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 97771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("ABCABCABC", get(server.url("/")).body().string()); 97871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("ABCABCABC", get(server.url("/")).body().string()); 97971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("DEFDEFDEF", get(server.url("/")).body().string()); 980e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 981e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 982e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** https://github.com/square/okhttp/issues/947 */ 983e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void gzipAndVaryOnAcceptEncoding() throws Exception { 984e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 985e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody(gzip("ABCABCABC")) 986e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Encoding: gzip") 987e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Encoding") 988e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 989e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 990e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("FAIL")); 991e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 99271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("ABCABCABC", get(server.url("/")).body().string()); 99371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("ABCABCABC", get(server.url("/")).body().string()); 994e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 995e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 996e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void conditionalCacheHitIsNotDoublePooled() throws Exception { 997e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 998e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("ETag: v1") 999e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1000e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1001e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .clearHeaders() 1002e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1003e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1004e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller ConnectionPool pool = ConnectionPool.getDefault(); 1005e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller pool.evictAll(); 1006e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setConnectionPool(pool); 1007e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 100871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 100971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1010e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, client.getConnectionPool().getConnectionCount()); 1011e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1012e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1013e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void expiresDateBeforeModifiedDate() throws Exception { 1014e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertConditionallyCached(new MockResponse() 1015e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1016e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 1017e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1018e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1019e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMaxAge() throws IOException { 1020e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1021e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1022e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 1023e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 1024e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 1025e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1026e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1027e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 102871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1029e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1030e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 103171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1032e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "max-age=30") 1033e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1034e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1035e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response.body().string()); 1036e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1037e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1038e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMinFresh() throws IOException { 1039e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1040e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1041e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1042e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1043e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1044e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1045e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 104671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1047e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1048e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 104971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1050e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "min-fresh=120") 1051e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1052e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1053e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response.body().string()); 1054e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1055e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1056e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMaxStale() throws IOException { 1057e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1058e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1059e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=120") 1060e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 1061e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1062e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1063e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 106471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1065e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1066e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 106771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1068e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "max-stale=180") 1069e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1070e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1071e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 1072e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("110 HttpURLConnection \"Response is stale\"", response.header("Warning")); 1073e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1074e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1075e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMaxStaleDirectiveWithNoValue() throws IOException { 1076e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Add a stale response to the cache. 1077e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1078e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1079e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=120") 1080e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 1081e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1082e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1083e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 108471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1085e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1086e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // With max-stale, we'll return that stale response. 1087e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 108871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1089e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "max-stale") 1090e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1091e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1092e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 1093e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("110 HttpURLConnection \"Response is stale\"", response.header("Warning")); 1094e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1095e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1096e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestMaxStaleNotHonoredWithMustRevalidate() throws IOException { 1097e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1098e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1099e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=120, must-revalidate") 1100e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 1101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1102e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1103e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 110471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1105e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1106e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 110771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1108e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "max-stale=180") 1109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1110e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1111e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response.body().string()); 1112e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1113e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1114e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestOnlyIfCachedWithNoResponseCached() throws IOException { 1115e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // (no responses enqueued) 1116e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1117e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 111871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1119e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "only-if-cached") 1120e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1121e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1122e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(response.body().source().exhausted()); 1123e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(504, response.code()); 1124e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getRequestCount()); 1125e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getNetworkCount()); 1126e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getHitCount()); 1127e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1128e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1129e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestOnlyIfCachedWithFullResponseCached() throws IOException { 1130e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1131e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1132e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=30") 1133e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1134e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 113571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1136e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 113771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1138e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "only-if-cached") 1139e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1140e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1141e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 1142e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getRequestCount()); 1143e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 1144e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getHitCount()); 1145e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1146e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1147e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestOnlyIfCachedWithConditionalResponseCached() throws IOException { 1148e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1149e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1150e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=30") 1151e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 1152e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 115371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1154e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 115571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1156e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "only-if-cached") 1157e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1158e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1159e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(response.body().source().exhausted()); 1160e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(504, response.code()); 1161e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getRequestCount()); 1162e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 1163e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getHitCount()); 1164e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1165e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1166e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 1167e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 117071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1171e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 117271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1173e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "only-if-cached") 1174e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1175e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1176e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(response.body().source().exhausted()); 1177e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(504, response.code()); 1178e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getRequestCount()); 1179e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 1180e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getHitCount()); 1181e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1182e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1183e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestCacheControlNoCache() throws Exception { 1184e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1185e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 1186e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 1187e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1188e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1189e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1190e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1191e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 119271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1193e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1194e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 1195e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1196e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Cache-Control", "no-cache") 1197e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1198e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1199e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response.body().string()); 1200e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1201e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1202e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void requestPragmaNoCache() throws Exception { 1203e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1204e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 1205e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 1206e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1207e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1208e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1209e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1210e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 121171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1212e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1213e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 1214e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1215e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Pragma", "no-cache") 1216e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1217e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1218e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response.body().string()); 1219e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1220e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1221e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void clientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 1222e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller MockResponse response = new MockResponse() 1223e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("ETag: v3") 1224e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0"); 1225e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 1226e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest request = 1227e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertClientSuppliedCondition(response, "If-Modified-Since", ifModifiedSinceDate); 1228e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(ifModifiedSinceDate, request.getHeader("If-Modified-Since")); 1229e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(request.getHeader("If-None-Match")); 1230e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1231e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1232e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void clientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 1233e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 1234e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller MockResponse response = new MockResponse() 1235e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedDate) 1236e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 1237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0"); 1238e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest request = assertClientSuppliedCondition(response, "If-None-Match", "v1"); 1239e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("v1", request.getHeader("If-None-Match")); 1240e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(request.getHeader("If-Modified-Since")); 1241e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1242e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1243e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 1244e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String conditionValue) throws Exception { 1245e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(seed.setBody("A")); 1246e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1247e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1248e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 124971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1250e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1251e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1252e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 1253e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1254e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header(conditionName, conditionValue) 1255e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1256e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1257e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, response.code()); 1258e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("", response.body().string()); 1259e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1260e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.takeRequest(); // seed 1261e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return server.takeRequest(); 1262e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1263e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 1265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * For Last-Modified and Date headers, we should echo the date back in the 1266e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * exact format we were served. 1267e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 1268e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void retainServedDateFormat() throws Exception { 1269e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Serve a response with a non-standard date format that OkHttp supports. 1270e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Date lastModifiedDate = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(-1)); 1271e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Date servedDate = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(-2)); 1272e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DateFormat dateFormat = new SimpleDateFormat("EEE dd-MMM-yyyy HH:mm:ss z", Locale.US); 1273e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller dateFormat.setTimeZone(TimeZone.getTimeZone("EDT")); 1274e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String lastModifiedString = dateFormat.format(lastModifiedDate); 1275e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String servedString = dateFormat.format(servedDate); 1276e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1277e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // This response should be conditionally cached. 1278e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1279e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + lastModifiedString) 1280e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + servedString) 1281e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1282e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1283e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1284e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 128571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 128671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1287e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1288e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // The first request has no conditions. 1289e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest request1 = server.takeRequest(); 1290e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(request1.getHeader("If-Modified-Since")); 1291e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1292e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // The 2nd request uses the server's date format. 1293e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller RecordedRequest request2 = server.takeRequest(); 1294e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedString, request2.getHeader("If-Modified-Since")); 1295e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1296e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1297e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void clientSuppliedConditionWithoutCachedResult() throws Exception { 1298e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1299e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1300e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1301e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 130271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")) 1303e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("If-Modified-Since", formatDate(-24, TimeUnit.HOURS)) 1304e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1305e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1306e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, response.code()); 1307e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("", response.body().string()); 1308e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1309e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1310e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void authorizationRequestFullyCached() throws Exception { 1311e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1312e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1313e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1314e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1315e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1316e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 131771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1318e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 1319e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1320e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Authorization", "password") 1321e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1322e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1323e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 1324e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1325e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1326e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1327e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void contentLocationDoesNotPopulateCache() throws Exception { 1328e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1329e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1330e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Location: /bar") 1331e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1332e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1333e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1334e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 133571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/foo")).body().string()); 133671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("B", get(server.url("/bar")).body().string()); 1337e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1338e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1339e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void connectionIsReturnedToPoolAfterConditionalSuccess() throws Exception { 1340e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1341e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1342e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1343e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1344e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1345e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1346e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1347e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1348e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 134971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/a")).body().string()); 135071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/a")).body().string()); 135171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("B", get(server.url("/b")).body().string()); 1352e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1353e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, server.takeRequest().getSequenceNumber()); 1354e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, server.takeRequest().getSequenceNumber()); 1355e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, server.takeRequest().getSequenceNumber()); 1356e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1357e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1358e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void statisticsConditionalCacheMiss() throws Exception { 1359e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1360e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1361e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1362e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1363e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1364e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1365e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1366e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("C")); 1367e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 136871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1369e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getRequestCount()); 1370e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 1371e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getHitCount()); 137271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("B", get(server.url("/")).body().string()); 137371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("C", get(server.url("/")).body().string()); 1374e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(3, cache.getRequestCount()); 1375e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(3, cache.getNetworkCount()); 1376e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getHitCount()); 1377e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1378e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1379e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void statisticsConditionalCacheHit() throws Exception { 1380e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1381e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1382e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1383e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1384e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1385e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1386e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1387e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1388e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 138971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1390e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getRequestCount()); 1391e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 1392e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getHitCount()); 139371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 139471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1395e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(3, cache.getRequestCount()); 1396e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(3, cache.getNetworkCount()); 1397e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getHitCount()); 1398e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1399e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1400e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void statisticsFullCacheHit() throws Exception { 1401e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1402e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1403e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1404e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 140571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1406e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getRequestCount()); 1407e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 1408e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.getHitCount()); 140971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 141071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1411e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(3, cache.getRequestCount()); 1412e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, cache.getNetworkCount()); 1413e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, cache.getHitCount()); 1414e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1415e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1416e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMatchesChangedRequestHeaderField() throws Exception { 1417e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1418e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1419e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Language") 1420e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1421e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1422e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1423e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 142471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1425e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request frRequest = new Request.Builder() 1426e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1427e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "fr-CA") 1428e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1429e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response frResponse = client.newCall(frRequest).execute(); 1430e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", frResponse.body().string()); 1431e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1432e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request enRequest = new Request.Builder() 1433e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1434e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "en-US") 1435e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1436e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response enResponse = client.newCall(enRequest).execute(); 1437e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", enResponse.body().string()); 1438e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1439e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1440e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMatchesUnchangedRequestHeaderField() throws Exception { 1441e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1442e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1443e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Language") 1444e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1445e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1446e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1447e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 144871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1449e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 1450e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1451e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "fr-CA") 1452e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1453e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request).execute(); 1454e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1455e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request1 = new Request.Builder() 1456e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1457e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "fr-CA") 1458e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1459e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request1).execute(); 1460e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1461e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1462e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1463e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMatchesAbsentRequestHeaderField() throws Exception { 1464e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1465e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1466e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Foo") 1467e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1468e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1469e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1470e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 147171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 147271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1473e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1474e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1475e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMatchesAddedRequestHeaderField() throws Exception { 1476e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1477e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1478e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Foo") 1479e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1480e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1481e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1482e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 148371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1484e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 148571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")).header("Foo", "bar") 1486e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1487e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1488e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response.body().string()); 1489e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1490e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1491e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMatchesRemovedRequestHeaderField() throws Exception { 1492e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1493e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1494e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Foo") 1495e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1496e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1497e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1498e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1499e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 150071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")).header("Foo", "bar") 1501e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1502e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response fooresponse = client.newCall(request).execute(); 1503e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", fooresponse.body().string()); 150471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("B", get(server.url("/")).body().string()); 1505e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1506e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1507e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyFieldsAreCaseInsensitive() throws Exception { 1508e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1509e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1510e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: ACCEPT-LANGUAGE") 1511e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1512e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1513e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1514e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 151571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1516e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 1517e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1518e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "fr-CA") 1519e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1520e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request).execute(); 1521e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1522e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request1 = new Request.Builder() 1523e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1524e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("accept-language", "fr-CA") 1525e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1526e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request1).execute(); 1527e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1528e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1529e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1530e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMultipleFieldsWithMatch() throws Exception { 1531e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1532e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1533e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Language, Accept-Charset") 1534e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Encoding") 1535e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1536e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1537e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1538e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 153971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1540e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 1541e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1542e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "fr-CA") 1543e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Charset", "UTF-8") 1544e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Encoding", "identity") 1545e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1546e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request).execute(); 1547e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1548e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request1 = new Request.Builder() 1549e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1550e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "fr-CA") 1551e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Charset", "UTF-8") 1552e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Encoding", "identity") 1553e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1554e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request1).execute(); 1555e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1556e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1557e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1558e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMultipleFieldsWithNoMatch() throws Exception { 1559e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1560e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1561e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Language, Accept-Charset") 1562e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Encoding") 1563e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1564e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1565e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1566e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 156771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1568e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request frRequest = new Request.Builder() 1569e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1570e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "fr-CA") 1571e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Charset", "UTF-8") 1572e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Encoding", "identity") 1573e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1574e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response frResponse = client.newCall(frRequest).execute(); 1575e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", frResponse.body().string()); 1576e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request enRequest = new Request.Builder() 1577e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1578e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "en-CA") 1579e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Charset", "UTF-8") 1580e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Encoding", "identity") 1581e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1582e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response enResponse = client.newCall(enRequest).execute(); 1583e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", enResponse.body().string()); 1584e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1585e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1586e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMultipleFieldValuesWithMatch() throws Exception { 1587e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1588e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1589e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Language") 1590e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1591e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1592e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1593e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 159471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1595e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request1 = new Request.Builder() 1596e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1597e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "fr-CA, fr-FR") 1598e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "en-US") 1599e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1600e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request1).execute(); 1601e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1602e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1603e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request2 = new Request.Builder() 1604e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1605e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "fr-CA, fr-FR") 1606e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "en-US") 1607e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1608e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request2).execute(); 1609e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1610e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1611e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1612e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyMultipleFieldValuesWithNoMatch() throws Exception { 1613e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1614e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1615e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Language") 1616e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1617e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1618e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1619e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 162071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1621e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request1 = new Request.Builder() 1622e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1623e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "fr-CA, fr-FR") 1624e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "en-US") 1625e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1626e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request1).execute(); 1627e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1628e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1629e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request2 = new Request.Builder() 1630e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1631e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "fr-CA") 1632e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Accept-Language", "en-US") 1633e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1634e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request2).execute(); 1635e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response2.body().string()); 1636e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1637e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1638e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyAsterisk() throws Exception { 163971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller server.enqueue(new MockResponse() 1640e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1641e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: *") 1642e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1643e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1644e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1645e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 164671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 164771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("B", get(server.url("/")).body().string()); 1648e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1649e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1650e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void varyAndHttps() throws Exception { 1651e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.useHttps(sslContext.getSocketFactory(), false); 1652e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1653e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1654e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Language") 1655e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1656e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1657e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1658e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1659e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setSslSocketFactory(sslContext.getSocketFactory()); 1660e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 1661e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 166271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1663e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request1 = new Request.Builder() 1664e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1665e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "en-US") 1666e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1667e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = client.newCall(request1).execute(); 1668e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1669e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1670e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request2 = new Request.Builder() 1671e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 1672e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .header("Accept-Language", "en-US") 1673e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1674e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = client.newCall(request2).execute(); 1675e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1676e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1677e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1678e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cachePlusCookies() throws Exception { 1679e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1680e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";") 1681e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1682e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1683e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1684e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1685e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";") 1686e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1687e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 168871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1689e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1690e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCookies(url, "a=FIRST"); 1691e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1692e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCookies(url, "a=SECOND"); 1693e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1694e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1695e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void getHeadersReturnsNetworkEndToEndHeaders() throws Exception { 1696e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1697e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Allow: GET, HEAD") 1698e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1699e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1700e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1701e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1702e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Allow: GET, HEAD, PUT") 1703e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1704e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 170571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/")); 1706e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1707e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("GET, HEAD", response1.header("Allow")); 1708e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 170971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/")); 1710e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1711e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("GET, HEAD, PUT", response2.header("Allow")); 1712e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1713e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1714e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void getHeadersReturnsCachedHopByHopHeaders() throws Exception { 1715e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1716e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Transfer-Encoding: identity") 1717e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1718e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1719e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1720e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1721e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Transfer-Encoding: none") 1722e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1723e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 172471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/")); 1725e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1726e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("identity", response1.header("Transfer-Encoding")); 1727e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 172871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/")); 1729e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1730e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("identity", response2.header("Transfer-Encoding")); 1731e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1732e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1733e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void getHeadersDeletesCached100LevelWarnings() throws Exception { 1734e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1735e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Warning: 199 test danger") 1736e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1737e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1738e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1739e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1740e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1741e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 174271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/")); 1743e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1744e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("199 test danger", response1.header("Warning")); 1745e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 174671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/")); 1747e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1748e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(null, response2.header("Warning")); 1749e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1750e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1751e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void getHeadersRetainsCached200LevelWarnings() throws Exception { 1752e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1753e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Warning: 299 test danger") 1754e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1755e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1756e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1757e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1758e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1759e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 176071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/")); 1761e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1762e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("299 test danger", response1.header("Warning")); 1763e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 176471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/")); 1765e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1766e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("299 test danger", response2.header("Warning")); 1767e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1768e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 176971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller public void assertCookies(HttpUrl url, String... expectedCookies) throws Exception { 1770e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller List<String> actualCookies = new ArrayList<>(); 177171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller for (HttpCookie cookie : cookieManager.getCookieStore().get(url.uri())) { 1772e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller actualCookies.add(cookie.toString()); 1773e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1774e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(Arrays.asList(expectedCookies), actualCookies); 1775e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1776e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1777e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void doNotCachePartialResponse() throws Exception { 1778e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNotCached(new MockResponse() 177971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 178071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 178171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .addHeader("Content-Range: bytes 100-100/200") 178271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .addHeader("Cache-Control: max-age=60")); 1783e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1784e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1785e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void conditionalHitUpdatesCache() throws Exception { 1786e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1787e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS)) 1788e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1789e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1790e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1791e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=30") 1792e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Allow: GET, HEAD") 1793e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1794e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1795e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1796e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1797e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // cache miss; seed the cache 179871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response1 = get(server.url("/a")); 1799e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 1800e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(null, response1.header("Allow")); 1801e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1802e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // conditional cache hit; update the cache 180371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response2 = get(server.url("/a")); 1804e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(HttpURLConnection.HTTP_OK, response2.code()); 1805e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 1806e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("GET, HEAD", response2.header("Allow")); 1807e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1808e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // full cache hit 180971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response3 = get(server.url("/a")); 1810e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response3.body().string()); 1811e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("GET, HEAD", response3.header("Allow")); 1812e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1813e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(2, server.getRequestCount()); 1814e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1815e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1816e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseSourceHeaderCached() throws IOException { 1817e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1818e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1819e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=30") 1820e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1821e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 182271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 1823e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 182471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .url(server.url("/")).header("Cache-Control", "only-if-cached") 1825e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 1826e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = client.newCall(request).execute(); 1827e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 1828e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1829e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1830e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseSourceHeaderConditionalCacheFetched() throws IOException { 1831e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1832e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1833e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=30") 1834e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(-31, TimeUnit.MINUTES))); 1835e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1836e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B") 1837e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=30") 1838e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1839e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 184071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 184171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response = get(server.url("/")); 1842e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response.body().string()); 1843e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1844e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1845e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseSourceHeaderConditionalCacheNotFetched() throws IOException { 1846e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1847e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A") 1848e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=0") 1849e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1850e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1851e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(304)); 1852e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 185371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(server.url("/")).body().string()); 185471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response = get(server.url("/")); 1855e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 1856e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1857e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1858e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void responseSourceHeaderFetched() throws IOException { 1859e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1860e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1861e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 186271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response = get(server.url("/")); 1863e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.body().string()); 1864e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1865e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1866e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void emptyResponseHeaderNameFromCacheIsLenient() throws Exception { 1867e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Headers.Builder headers = new Headers.Builder() 1868e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .add("Cache-Control: max-age=120"); 1869e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Internal.instance.addLenient(headers, ": A"); 1870e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1871e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setHeaders(headers.build()) 1872e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("body")); 1873e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 187471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller Response response = get(server.url("/")); 1875e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response.header("")); 1876e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1877e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1878e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 1879e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Old implementations of OkHttp's response cache wrote header fields like 1880e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * ":status: 200 OK". This broke our cached response parser because it split 1881e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * on the first colon. This regression test exists to help us read these old 1882e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * bad cache entries. 1883e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 1884e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * https://github.com/square/okhttp/issues/227 1885e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 1886e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void testGoldenCacheResponse() throws Exception { 1887e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 1888e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1889e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .clearHeaders() 1890e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1891e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 189271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1893e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String urlKey = Util.md5Hex(url.toString()); 1894e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String entryMetadata = "" 1895e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "" + url + "\n" 1896e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "GET\n" 1897e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "0\n" 1898e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "HTTP/1.1 200 OK\n" 1899e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "7\n" 1900e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + ":status: 200 OK\n" 1901e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + ":version: HTTP/1.1\n" 1902e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "etag: foo\n" 1903e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "content-length: 3\n" 1904e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "OkHttp-Received-Millis: " + System.currentTimeMillis() + "\n" 1905e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "X-Android-Response-Source: NETWORK 200\n" 1906e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "OkHttp-Sent-Millis: " + System.currentTimeMillis() + "\n" 1907e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "\n" 1908e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\n" 1909e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "1\n" 1910e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "MIIBpDCCAQ2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1qd2lsc29uLmxvY2FsMB4XDTEzMDgy" 1911e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "OTA1MDE1OVoXDTEzMDgzMDA1MDE1OVowGDEWMBQGA1UEAxMNandpbHNvbi5sb2NhbDCBnzANBgkqhkiG9w0BAQEF" 1912e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "AAOBjQAwgYkCgYEAlFW+rGo/YikCcRghOyKkJanmVmJSce/p2/jH1QvNIFKizZdh8AKNwojt3ywRWaDULA/RlCUc" 1913e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "ltF3HGNsCyjQI/+Lf40x7JpxXF8oim1E6EtDoYtGWAseelawus3IQ13nmo6nWzfyCA55KhAWf4VipelEy8DjcuFK" 1914e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "v6L0xwXnI0ECAwEAATANBgkqhkiG9w0BAQsFAAOBgQAuluNyPo1HksU3+Mr/PyRQIQS4BI7pRXN8mcejXmqyscdP" 1915e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "7S6J21FBFeRR8/XNjVOp4HT9uSc2hrRtTEHEZCmpyoxixbnM706ikTmC7SN/GgM+SmcoJ1ipJcNcl8N0X6zym4dm" 1916e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "yFfXKHu2PkTo7QFdpOJFvP3lIigcSZXozfmEDg==\n" 1917e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "-1\n"; 1918e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String entryBody = "abc"; 1919e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String journalBody = "" 1920e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "libcore.io.DiskLruCache\n" 1921e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "1\n" 1922e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "201105\n" 1923e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "2\n" 1924e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "\n" 1925e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "CLEAN " + urlKey + " " + entryMetadata.length() + " " + entryBody.length() + "\n"; 1926e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(cache.getDirectory(), urlKey + ".0", entryMetadata); 1927e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(cache.getDirectory(), urlKey + ".1", entryBody); 1928e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(cache.getDirectory(), "journal", journalBody); 192971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller cache = new Cache(cache.getDirectory(), Integer.MAX_VALUE, fileSystem); 1930e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.setCache(cache); 1931e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1932e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response = get(url); 1933e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(entryBody, response.body().string()); 1934e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("3", response.header("Content-Length")); 1935e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("foo", response.header("etag")); 1936e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1937e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1938e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictAll() throws Exception { 1939e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1940e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1941e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1942e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1943e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 1944e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 194571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1946e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1947e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.getCache().evictAll(); 1948e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, client.getCache().getSize()); 1949e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", get(url).body().string()); 1950e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1951e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1952e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void networkInterceptorInvokedForConditionalGet() throws Exception { 1953e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1954e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("ETag: v1") 1955e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1956e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1957e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1958e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1959e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Seed the cache. 196071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1961e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1962e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1963e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller final AtomicReference<String> ifNoneMatch = new AtomicReference<>(); 1964e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.networkInterceptors().add(new Interceptor() { 1965e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override public Response intercept(Chain chain) throws IOException { 1966e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller ifNoneMatch.compareAndSet(null, chain.request().header("If-None-Match")); 1967e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return chain.proceed(chain.request()); 1968e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1969e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller }); 1970e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1971e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Confirm the value is cached and intercepted. 1972e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1973e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("v1", ifNoneMatch.get()); 1974e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1975e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1976e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void networkInterceptorNotInvokedForFullyCached() throws Exception { 1977e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1978e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 1979e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("A")); 1980e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1981e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Seed the cache. 198271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 1983e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1984e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1985e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Confirm the interceptor isn't exercised. 1986e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.networkInterceptors().add(new Interceptor() { 1987e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override public Response intercept(Chain chain) throws IOException { 1988e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller throw new AssertionError(); 1989e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1990e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller }); 1991e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 1992e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1993e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1994e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iterateCache() throws Exception { 1995e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Put some responses in the cache. 1996e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 1997e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 199871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl urlA = server.url("/a"); 1999e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(urlA).body().string()); 2000e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2001e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2002e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("b")); 200371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl urlB = server.url("/b"); 2004e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("b", get(urlB).body().string()); 2005e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2006e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2007e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("c")); 200871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl urlC = server.url("/c"); 2009e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("c", get(urlC).body().string()); 2010e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2011e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Confirm the iterator returns those responses... 2012e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<String> i = cache.urls(); 2013e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(i.hasNext()); 2014e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(urlA.toString(), i.next()); 2015e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(i.hasNext()); 2016e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(urlB.toString(), i.next()); 2017e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(i.hasNext()); 2018e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(urlC.toString(), i.next()); 2019e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2020e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // ... and nothing else. 2021e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFalse(i.hasNext()); 2022e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 2023e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller i.next(); 2024e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 2025e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (NoSuchElementException expected) { 2026e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2027e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2028e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2029e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorRemoveFromCache() throws Exception { 2030e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Put a response in the cache. 2031e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2032e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60") 2033e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 203471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/a"); 2035e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 2036e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2037e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Remove it with iteration. 2038e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<String> i = cache.urls(); 2039e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(url.toString(), i.next()); 2040e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller i.remove(); 2041e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2042e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Confirm that subsequent requests suffer a cache miss. 2043e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2044e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("b")); 2045e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("b", get(url).body().string()); 2046e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2047e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2048e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorRemoveWithoutNextThrows() throws Exception { 2049e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Put a response in the cache. 2050e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2051e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 205271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/a"); 2053e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 2054e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2055e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<String> i = cache.urls(); 2056e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(i.hasNext()); 2057e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 2058e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller i.remove(); 2059e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 2060e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 2061e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2062e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2063e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2064e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorRemoveOncePerCallToNext() throws Exception { 2065e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Put a response in the cache. 2066e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2067e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 206871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/a"); 2069e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 2070e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2071e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<String> i = cache.urls(); 2072e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(url.toString(), i.next()); 2073e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller i.remove(); 2074e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2075e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Too many calls to remove(). 2076e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 2077e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller i.remove(); 2078e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 2079e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 2080e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2081e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2082e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2083e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void elementEvictedBetweenHasNextAndNext() throws Exception { 2084e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Put a response in the cache. 2085e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2086e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 208771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/a"); 2088e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 2089e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2090e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // The URL will remain available if hasNext() returned true... 2091e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<String> i = cache.urls(); 2092e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(i.hasNext()); 2093e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2094e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // ...so even when we evict the element, we still get something back. 2095e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.evictAll(); 2096e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(url.toString(), i.next()); 2097e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2098e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Remove does nothing. But most importantly, it doesn't throw! 2099e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller i.remove(); 2100e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2102e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void elementEvictedBeforeHasNextIsOmitted() throws Exception { 2103e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Put a response in the cache. 2104e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2105e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("a")); 210671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/a"); 2107e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", get(url).body().string()); 2108e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<String> i = cache.urls(); 2110e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.evictAll(); 2111e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2112e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // The URL was evicted before hasNext() made any promises. 2113e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFalse(i.hasNext()); 2114e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 2115e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller i.next(); 2116e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 2117e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (NoSuchElementException expected) { 2118e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2119e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2120e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 212171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller /** Test https://github.com/square/okhttp/issues/1712. */ 212271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller @Test public void conditionalMissUpdatesCache() throws Exception { 212371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller server.enqueue(new MockResponse() 212471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .addHeader("ETag: v1") 212571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .setBody("A")); 212671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller server.enqueue(new MockResponse() 212771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 212871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller server.enqueue(new MockResponse() 212971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .addHeader("ETag: v2") 213071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .setBody("B")); 213171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller server.enqueue(new MockResponse() 213271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 213371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller 213471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 213571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(url).body().string()); 213671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("A", get(url).body().string()); 213771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("B", get(url).body().string()); 213871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("B", get(url).body().string()); 213971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller 214071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals(null, server.takeRequest().getHeader("If-None-Match")); 214171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("v1", server.takeRequest().getHeader("If-None-Match")); 214271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("v1", server.takeRequest().getHeader("If-None-Match")); 214371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller assertEquals("v2", server.takeRequest().getHeader("If-None-Match")); 214471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller } 214571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller 214671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller private Response get(HttpUrl url) throws IOException { 2147e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Request request = new Request.Builder() 2148e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .url(url) 2149e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .build(); 2150e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return client.newCall(request).execute(); 2151e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2152e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2153e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2154e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void writeFile(File directory, String file, String content) throws IOException { 215571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller BufferedSink sink = Okio.buffer(fileSystem.sink(new File(directory, file))); 2156e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.writeUtf8(content); 2157e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.close(); 2158e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2159e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2160e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 2161e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * @param delta the offset from the current date to use. Negative 2162e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * values yield dates in the past; positive values yield dates in the 2163e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * future. 2164e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 2165e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private String formatDate(long delta, TimeUnit timeUnit) { 2166e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta))); 2167e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private String formatDate(Date date) { 2170e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 2171e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller rfc1123.setTimeZone(TimeZone.getTimeZone("GMT")); 2172e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return rfc1123.format(date); 2173e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2174e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2175e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertNotCached(MockResponse response) throws Exception { 2176e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(response.setBody("A")); 2177e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2178e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("B")); 2179e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 218071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 2181e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 2182e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", get(url).body().string()); 2183e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2184e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2185e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** @return the request with the conditional get headers. */ 2186e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 2187e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // scenario 1: condition succeeds 2188e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(response.setBody("A").setStatus("HTTP/1.1 200 A-OK")); 2189e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2190e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 2191e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2192e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // scenario 2: condition fails 2193e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(response.setBody("B") 2194e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setStatus("HTTP/1.1 200 B-OK")); 2195e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 2196e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setStatus("HTTP/1.1 200 C-OK") 2197e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("C")); 2198e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 219971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl valid = server.url("/valid"); 2200e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response1 = get(valid); 2201e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response1.body().string()); 2202e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(HttpURLConnection.HTTP_OK, response1.code()); 2203e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A-OK", response1.message()); 2204e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response2 = get(valid); 2205e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", response2.body().string()); 2206e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(HttpURLConnection.HTTP_OK, response2.code()); 2207e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A-OK", response2.message()); 2208e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 220971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl invalid = server.url("/invalid"); 2210e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response3 = get(invalid); 2211e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", response3.body().string()); 2212e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(HttpURLConnection.HTTP_OK, response3.code()); 2213e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B-OK", response3.message()); 2214e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Response response4 = get(invalid); 2215e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("C", response4.body().string()); 2216e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(HttpURLConnection.HTTP_OK, response4.code()); 2217e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("C-OK", response4.message()); 2218e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2219e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.takeRequest(); // regular get 2220e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return server.takeRequest(); // conditional get 2221e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2222e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2223e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertFullyCached(MockResponse response) throws Exception { 2224e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(response.setBody("A")); 2225e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(response.setBody("B")); 2226e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 222771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller HttpUrl url = server.url("/"); 2228e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 2229e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", get(url).body().string()); 2230e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2231e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2232e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 2233e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Shortens the body of {@code response} but not the corresponding headers. 2234e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Only useful to test how clients respond to the premature conclusion of 2235e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * the HTTP body. 2236e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 2237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 2238e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setSocketPolicy(DISCONNECT_AT_END); 2239e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Headers headers = response.getHeaders(); 2240e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Buffer truncatedBody = new Buffer(); 2241e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller truncatedBody.write(response.getBody(), numBytesToKeep); 2242e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setBody(truncatedBody); 2243e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setHeaders(headers); 2244e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return response; 2245e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2246e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2247e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller enum TransferKind { 2248e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller CHUNKED() { 2249e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override void setBody(MockResponse response, Buffer content, int chunkSize) 2250e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller throws IOException { 2251e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setChunkedBody(content, chunkSize); 2252e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2253e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller }, 2254e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller FIXED_LENGTH() { 2255e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override void setBody(MockResponse response, Buffer content, int chunkSize) { 2256e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setBody(content); 2257e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2258e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller }, 2259e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller END_OF_STREAM() { 2260e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override void setBody(MockResponse response, Buffer content, int chunkSize) { 2261e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setBody(content); 2262e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setSocketPolicy(DISCONNECT_AT_END); 2263e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.removeHeader("Content-Length"); 2264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller }; 2266e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2267e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller abstract void setBody(MockResponse response, Buffer content, int chunkSize) throws IOException; 2268e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2269e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller void setBody(MockResponse response, String content, int chunkSize) throws IOException { 2270e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setBody(response, new Buffer().writeUtf8(content), chunkSize); 2271e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2272e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2273e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 2274e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** Returns a gzipped copy of {@code bytes}. */ 2275e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller public Buffer gzip(String data) throws IOException { 2276e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Buffer result = new Buffer(); 2277e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSink sink = Okio.buffer(new GzipSink(result)); 2278e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.writeUtf8(data); 2279e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.close(); 2280e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return result; 2281e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 2282e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller} 2283