17899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath/* 27899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Copyright (C) 2011 The Android Open Source Project 37899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 47899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 57899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * you may not use this file except in compliance with the License. 67899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * You may obtain a copy of the License at 77899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 87899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 97899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Unless required by applicable law or agreed to in writing, software 117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * See the License for the specific language governing permissions and 147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * limitations under the License. 157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 172231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpackage com.squareup.okhttp.internal.http; 187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 19c6bd683320121544811f481709b3fdbcbe9b3866Neil Fullerimport com.squareup.okhttp.ConnectionPool; 20faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport com.squareup.okhttp.HttpResponseCache; 212231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.OkHttpClient; 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.OkResponseCache; 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.Request; 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.Response; 25faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport com.squareup.okhttp.ResponseSource; 262231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.SslContextBuilder; 27166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.internal.Util; 28166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.MockResponse; 29166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.MockWebServer; 30166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.RecordedRequest; 317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.BufferedReader; 327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.ByteArrayOutputStream; 337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.File; 347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.FileNotFoundException; 35166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport java.io.FileOutputStream; 367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.IOException; 377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStream; 387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStreamReader; 397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.OutputStream; 407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CacheRequest; 417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieHandler; 427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieManager; 437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpCookie; 447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpURLConnection; 457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.ResponseCache; 467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URISyntaxException; 477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URL; 487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URLConnection; 492231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.Principal; 502231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.cert.Certificate; 517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.DateFormat; 527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.SimpleDateFormat; 537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.ArrayList; 547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Arrays; 557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Date; 564944713f5c5b141966ac82973d6a31a634e8e01eNeil Fullerimport java.util.HashMap; 577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Iterator; 587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.List; 597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Locale; 607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.TimeZone; 617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.UUID; 627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.TimeUnit; 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.concurrent.atomic.AtomicBoolean; 647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.atomic.AtomicInteger; 657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.atomic.AtomicReference; 667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.zip.GZIPOutputStream; 672231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.HostnameVerifier; 682231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.HttpsURLConnection; 692231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.SSLContext; 702231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.SSLSession; 712231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport org.junit.After; 7254cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport org.junit.Before; 7354cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport org.junit.Test; 7454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport static com.squareup.okhttp.mockwebserver.SocketPolicy.DISCONNECT_AT_END; 762231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertEquals; 772231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertFalse; 782231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertNotNull; 792231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertNull; 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertSame; 812231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertTrue; 822231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.fail; 837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/** 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Android's HttpResponseCacheTest. This tests both the {@link HttpResponseCache} implementation and 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * the behavior of {@link com.squareup.okhttp.OkResponseCache} classes generally. 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 882231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpublic final class HttpResponseCacheTest { 8954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final HostnameVerifier NULL_HOSTNAME_VERIFIER = new HostnameVerifier() { 9054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public boolean verify(String s, SSLSession sslSession) { 9154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return true; 9254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 9354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private static final SSLContext sslContext = SslContextBuilder.localhost(); 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 9754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final OkHttpClient client = new OkHttpClient(); 9854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private MockWebServer server = new MockWebServer(); 9974623587bf099735cf16ec2298005f12fd3fcb07jwilson private MockWebServer server2 = new MockWebServer(); 10054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private HttpResponseCache cache; 10154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final CookieManager cookieManager = new CookieManager(); 10254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 10354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Before public void setUp() throws Exception { 10454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String tmp = System.getProperty("java.io.tmpdir"); 10554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); 10654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE); 10754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(cache); 10854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(cookieManager); 109166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.setNpnEnabled(false); 11054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 11154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 11254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @After public void tearDown() throws Exception { 11354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.shutdown(); 11474623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.shutdown(); 11554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(null); 116faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath cache.delete(); 11754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(null); 11854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 11954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 12054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private HttpURLConnection openConnection(URL url) { 12154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return client.open(url); 12254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 12354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void responseCacheAccessWithOkHttpMember() throws IOException { 1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ResponseCache.setDefault(null); 1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller client.setResponseCache(cache); 1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertSame(cache, client.getOkResponseCache()); 1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNull(client.getResponseCache()); 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void responseCacheAccessWithGlobalDefault() throws IOException { 1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ResponseCache.setDefault(cache); 1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller client.setResponseCache(null); 1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNull(client.getOkResponseCache()); 1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNull(client.getResponseCache()); 1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 13854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 13954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Test that response caching is consistent with the RI and the spec. 14054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 14154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 14254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingByResponseCode() throws Exception { 14354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Test each documented HTTP/1.1 code, plus the first unused value in each range. 14454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 14554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 14654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We can't test 100 because it's not really a response. 14754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // assertCached(false, 100); 14854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 101); 14954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 102); 15054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 200); 15154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 201); 15254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 202); 15354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 203); 15454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 204); 15554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 205); 15654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 206); // we don't cache partial responses 15754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 207); 15854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 300); 15954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 301); 16054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 302; i <= 308; ++i) { 16154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 16254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 400; i <= 406; ++i) { 16454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (See test_responseCaching_407.) 16754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 408); 16854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 409); 16954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (See test_responseCaching_410.) 17054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 411; i <= 418; ++i) { 17154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 17254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 17354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 500; i <= 506; ++i) { 17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 17554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 17854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 17954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Response code 407 should only come from proxy servers. Android's client 18054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * throws if it is sent by an origin server. 18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 18254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void originServerSends407() throws Exception { 18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(407)); 18454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 18554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection conn = openConnection(url); 18854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson conn.getResponseCode(); 19054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 19154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 19254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 19354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 19454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 19554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCaching_410() throws Exception { 19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // the HTTP spec permits caching 410s, but the RI doesn't. 19754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 410); 19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 19954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertCached(boolean shouldPut, int responseCode) throws Exception { 20154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server = new MockWebServer(); 20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 20354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 20554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(responseCode) 20654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABCDE") 20754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("WWW-Authenticate: challenge"); 20854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) { 20954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("Proxy-Authenticate: Basic realm=\"protected area\""); 21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { 21154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("WWW-Authenticate: Basic realm=\"protected area\""); 21254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 21354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection conn = openConnection(url); 21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(responseCode, conn.getResponseCode()); 21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // exhaust the content stream 22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(conn); 22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 2233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Response cached = cache.get(new Request.Builder().url(url).build()); 22454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (shouldPut) { 22554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotNull(Integer.toString(responseCode), cached); 2263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller cached.body().close(); 22754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 22854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(Integer.toString(responseCode), cached); 22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 23254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 23354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 23454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Test that we can interrogate the response when the cache is being 23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * populated. http://code.google.com/p/android/issues/detail?id=7787 23654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 23754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCacheCallbackApis() throws Exception { 23854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final String body = "ABCDE"; 23954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final AtomicInteger cacheCount = new AtomicInteger(); 24054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 2413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.enqueue(new MockResponse() 2423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .setStatus("HTTP/1.1 200 Fantastic") 2433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .addHeader("Content-Type: text/plain") 2443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .addHeader("fgh: ijk") 2453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .setBody(body)); 2463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.play(); 2473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller client.setOkResponseCache(new AbstractOkResponseCache() { 2493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public CacheRequest put(Response response) throws IOException { 2503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(server.getUrl("/"), response.request().url()); 2513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(200, response.code()); 2523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNull(response.body()); 2533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("5", response.header("Content-Length")); 2543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("text/plain", response.header("Content-Type")); 2553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("ijk", response.header("fgh")); 25654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cacheCount.incrementAndGet(); 25754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 25854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }); 26054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 26154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 26254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(url); 26354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(body, readAscii(connection)); 26454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cacheCount.get()); 26554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 26654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 2673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Don't explode if the cache returns a null body. http://b/3373699 */ 2683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void responseCacheReturnsNullOutputStream() throws Exception { 2693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller final AtomicBoolean aborted = new AtomicBoolean(); 2703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller client.setOkResponseCache(new AbstractOkResponseCache() { 2713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public CacheRequest put(Response response) throws IOException { 2723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new CacheRequest() { 2733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void abort() { 2743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller aborted.set(true); 2753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public OutputStream getBody() throws IOException { 2783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; 2793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller }; 2813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller }); 2833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.enqueue(new MockResponse().setBody("abcdef")); 2853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.play(); 2863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 2883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("abc", readAscii(connection, 3)); 2893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller connection.getInputStream().close(); 2903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertFalse(aborted.get()); // The best behavior is ambiguous, but RI 6 doesn't abort here 2913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 2923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithFixedLength() throws IOException { 29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.FIXED_LENGTH); 29554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 29854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.CHUNKED); 29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 30054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 30254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.END_OF_STREAM); 30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 30454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 30554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 30654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://code.google.com/p/android/issues/detail?id=8175 30854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 30954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testResponseCaching(TransferKind transferKind) throws IOException { 31054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 31354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setStatus("HTTP/1.1 200 Fantastic"); 31454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 31654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 31854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Make sure that calling skip() doesn't omit bytes from the cache. 31954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection urlConnection = openConnection(server.getUrl("/")); 32054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = urlConnection.getInputStream(); 32154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love ", readAscii(urlConnection, "I love ".length())); 32254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reliableSkip(in, "puppies but hate ".length()); 32354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("spiders", readAscii(urlConnection, "spiders".length())); 32454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 32554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 32654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 32754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 32854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 32954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson urlConnection = openConnection(server.getUrl("/")); // cached! 33054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in = urlConnection.getInputStream(); 33154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love puppies but hate spiders", 33254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(urlConnection, "I love puppies but hate spiders".length())); 33354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(200, urlConnection.getResponseCode()); 33454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 33554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 33654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 33754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 33854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 33954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 34054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 34154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 34254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 34354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 34454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCaching() throws IOException { 34554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 34654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 34754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 34854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 34954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 35054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 3513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller HttpsURLConnection c1 = (HttpsURLConnection) client.open(server.getUrl("/")); 3523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c1.setSSLSocketFactory(sslContext.getSocketFactory()); 3533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 3543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("ABC", readAscii(c1)); 35554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 35654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 3573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String suite = c1.getCipherSuite(); 3583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Certificate> localCerts = toListOrNull(c1.getLocalCertificates()); 3593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Certificate> serverCerts = toListOrNull(c1.getServerCertificates()); 3603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Principal peerPrincipal = c1.getPeerPrincipal(); 3613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Principal localPrincipal = c1.getLocalPrincipal(); 3623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 3633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller HttpsURLConnection c2 = (HttpsURLConnection) client.open(server.getUrl("/")); // cached! 3643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c2.setSSLSocketFactory(sslContext.getSocketFactory()); 3653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 3663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("ABC", readAscii(c2)); 36754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 36854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 36954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 37054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 37154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 3723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(suite, c2.getCipherSuite()); 3733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(localCerts, toListOrNull(c2.getLocalCertificates())); 3743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(serverCerts, toListOrNull(c2.getServerCertificates())); 3753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(peerPrincipal, c2.getPeerPrincipal()); 3763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(localPrincipal, c2.getLocalPrincipal()); 37754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 37854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 37954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndRedirects() throws Exception { 38054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 38154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 38254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 38354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 38454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 38554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 38654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 38754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 38854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 38954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 39154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 39254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = openConnection(server.getUrl("/")); // cached! 39454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 39554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects 39754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getNetworkCount()); 39854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 39954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 40054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 40154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void redirectToCachedResult() throws Exception { 40254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("ABC")); 40354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 40454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 40554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 40654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 40754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 40854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(openConnection(server.getUrl("/foo")))); 40954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request1 = server.takeRequest(); 41054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /foo HTTP/1.1", request1.getRequestLine()); 41154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, request1.getSequenceNumber()); 41254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 41354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(openConnection(server.getUrl("/bar")))); 41454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request2 = server.takeRequest(); 41554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /bar HTTP/1.1", request2.getRequestLine()); 41654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, request2.getSequenceNumber()); 41754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 41854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // an unrelated request should reuse the pooled connection 41954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("DEF", readAscii(openConnection(server.getUrl("/baz")))); 42054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request3 = server.takeRequest(); 42154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /baz HTTP/1.1", request3.getRequestLine()); 42254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, request3.getSequenceNumber()); 42354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 42454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 42554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCachingAndRedirects() throws IOException { 42654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 42754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 42854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 42954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 43054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 43154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 43254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 43354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 43454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 43554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 43654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 437166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath client.setSslSocketFactory(sslContext.getSocketFactory()); 438166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 439166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 44054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(server.getUrl("/")); 44154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection1)); 4423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNotNull(connection1.getCipherSuite()); 44354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 44454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Cached! 44554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(server.getUrl("/")); 44654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection2)); 4473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNotNull(connection2.getCipherSuite()); 44854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 44954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 45054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 4513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(connection1.getCipherSuite(), connection2.getCipherSuite()); 45274623587bf099735cf16ec2298005f12fd3fcb07jwilson } 45374623587bf099735cf16ec2298005f12fd3fcb07jwilson 45474623587bf099735cf16ec2298005f12fd3fcb07jwilson /** 45574623587bf099735cf16ec2298005f12fd3fcb07jwilson * We've had bugs where caching and cross-protocol redirects yield class 45674623587bf099735cf16ec2298005f12fd3fcb07jwilson * cast exceptions internal to the cache because we incorrectly assumed that 45774623587bf099735cf16ec2298005f12fd3fcb07jwilson * HttpsURLConnection was always HTTPS and HttpURLConnection was always HTTP; 45874623587bf099735cf16ec2298005f12fd3fcb07jwilson * in practice redirects mean that each can do either. 45974623587bf099735cf16ec2298005f12fd3fcb07jwilson * 46074623587bf099735cf16ec2298005f12fd3fcb07jwilson * https://github.com/square/okhttp/issues/214 46174623587bf099735cf16ec2298005f12fd3fcb07jwilson */ 46274623587bf099735cf16ec2298005f12fd3fcb07jwilson @Test public void secureResponseCachingAndProtocolRedirects() throws IOException { 46374623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.useHttps(sslContext.getSocketFactory(), false); 46474623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 46574623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 46674623587bf099735cf16ec2298005f12fd3fcb07jwilson .setBody("ABC")); 46774623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.enqueue(new MockResponse().setBody("DEF")); 46874623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.play(); 46974623587bf099735cf16ec2298005f12fd3fcb07jwilson 47074623587bf099735cf16ec2298005f12fd3fcb07jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 47174623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 47274623587bf099735cf16ec2298005f12fd3fcb07jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 47374623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Location: " + server2.getUrl("/"))); 47474623587bf099735cf16ec2298005f12fd3fcb07jwilson server.play(); 47574623587bf099735cf16ec2298005f12fd3fcb07jwilson 47674623587bf099735cf16ec2298005f12fd3fcb07jwilson client.setSslSocketFactory(sslContext.getSocketFactory()); 47774623587bf099735cf16ec2298005f12fd3fcb07jwilson client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 47874623587bf099735cf16ec2298005f12fd3fcb07jwilson 47974623587bf099735cf16ec2298005f12fd3fcb07jwilson HttpURLConnection connection1 = client.open(server.getUrl("/")); 48074623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals("ABC", readAscii(connection1)); 48174623587bf099735cf16ec2298005f12fd3fcb07jwilson 48274623587bf099735cf16ec2298005f12fd3fcb07jwilson // Cached! 48374623587bf099735cf16ec2298005f12fd3fcb07jwilson HttpURLConnection connection2 = client.open(server.getUrl("/")); 48474623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals("ABC", readAscii(connection2)); 48574623587bf099735cf16ec2298005f12fd3fcb07jwilson 48674623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 48774623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals(2, cache.getHitCount()); 48854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 48954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 49054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCacheRequestHeaders() throws IOException, URISyntaxException { 49154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("ABC")); 49254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 49354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 4943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller final AtomicReference<Request> requestRef = new AtomicReference<Request>(); 4953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller client.setOkResponseCache(new AbstractOkResponseCache() { 4963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public Response get(Request request) throws IOException { 4973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller requestRef.set(request); 49854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 49954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 50054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }); 50154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 50254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 50354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection urlConnection = openConnection(url); 50454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson urlConnection.addRequestProperty("A", "android"); 50554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(urlConnection); 5063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(Arrays.asList("android"), requestRef.get().headers("A")); 50754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 50854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 50954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 51054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 51154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 51254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 51354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 51454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.CHUNKED); 51554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 51654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 51754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 51854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Intentionally empty. This case doesn't make sense because there's no 51954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // such thing as a premature disconnect when the disconnect itself 52054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // indicates the end of the data stream. 52154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 52254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 52454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse(); 52554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 52654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(truncateViolently(response, 16)); 52754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 52854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 52954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 53054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson BufferedReader reader = new BufferedReader( 53154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new InputStreamReader(openConnection(server.getUrl("/")).getInputStream())); 53254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", reader.readLine()); 53354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 53454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.readLine(); 53554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("This implementation silently ignored a truncated HTTP body."); 53654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 53754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 53854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.close(); 53954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 54054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 54154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 54254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 54354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 54454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 54554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 54654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 54754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 54854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 54954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithContentLengthHeader() throws IOException { 55054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 55154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 55254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 55354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithChunkedEncoding() throws IOException { 55454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.CHUNKED); 55554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 55654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 55754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithNoLengthHeaders() throws IOException { 55854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 55954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 56054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 56154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 56254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Setting a low transfer speed ensures that stream discarding will time out. 5633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller MockResponse response = new MockResponse().throttleBody(6, 1, TimeUnit.SECONDS); 56454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 56554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 56654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 56754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 56854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 56954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 57054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = connection.getInputStream(); 57154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", readAscii(connection, 5)); 57254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 57354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 57454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.read(); 57554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("Expected an IOException because the stream is closed."); 57654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 57754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 57854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 57954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 58054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 58154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = openConnection(server.getUrl("/")); 58254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 58354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 58454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 58554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 58654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 58754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 58854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 seconds ago 58954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 seconds ago 59054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 seconds 59154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds from now 59254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 59354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 59454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 59554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 59654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 59754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 59854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 59954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 60054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 60154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 60254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(connection.getHeaderField("Warning")); 60354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 60454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 60554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateConditionallyCached() throws Exception { 60654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 115 seconds ago 60754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 15 seconds ago 60854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (115 - 15) / 10 = 10 seconds 60954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds ago 61054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 61154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 61254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 61354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 61454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 61554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 61654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 61754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 61854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 61954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 days ago 62054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 days ago 62154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 days 62254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 days from served date = 5 days from now 62354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 62454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 62554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 62654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 62754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 62854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 62954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 63054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 63154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 63254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 63354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 63454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 63554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void noDefaultExpirationForUrlsWithQueryString() throws Exception { 63654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 63754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 63854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 63954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 64054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 64154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 64254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 64354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/?foo=bar"); 64454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 64554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 64654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 64754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 64854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithLastModifiedHeader() throws Exception { 64954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 65054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 65154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 65254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 65354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 65454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 65554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 65654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 65754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithNoLastModifiedHeader() throws Exception { 65854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 65954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 66054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 66154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInTheFuture() throws Exception { 66254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 66354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 66454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 66554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredWithMaxAgeAndExpires() throws Exception { 66654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 66754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 66854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 66954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 67054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 67154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 67254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 67354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 67454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 67554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 67654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 67754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 67854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 67954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 68054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 68154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 68254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Chrome interprets max-age relative to the local clock. Both our cache 68354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // and Firefox both use the earlier of the local and server's clock. 68454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 68554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 68654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 68754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 68854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateHeader() throws Exception { 68954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 69054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 69154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 69254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 69354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithNoDateHeader() throws Exception { 69454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Cache-Control: max-age=60")); 69554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 69654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 69754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeWithLastModifiedButNoServedDate() throws Exception { 69854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 69954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 70054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 70154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 70254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 70354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 70454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 70554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 70654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 70754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 70854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 70954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 71054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverLowerSharedMaxAge() throws Exception { 71154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 71254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=60") 71354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=180")); 71454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 71554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 71654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverHigherMaxAge() throws Exception { 71754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 71854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=180") 71954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 72054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 72154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodOptionsIsNotCached() throws Exception { 72354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("OPTIONS", false); 72454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 72554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodGetIsCached() throws Exception { 72754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("GET", true); 72854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 72954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 73054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodHeadIsNotCached() throws Exception { 73154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 73254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("HEAD", false); 73354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 73454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 73554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPostIsNotCached() throws Exception { 73654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 73754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("POST", false); 73854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 73954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPutIsNotCached() throws Exception { 74154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("PUT", false); 74254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodDeleteIsNotCached() throws Exception { 74554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("DELETE", false); 74654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodTraceIsNotCached() throws Exception { 74954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("TRACE", false); 75054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 75154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 75354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache (potentially) 75454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. expect a cache hit or miss 75554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 75654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("X-Response-ID: 1")); 75754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("X-Response-ID: 2")); 75854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 75954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 76154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection request1 = openConnection(url); 76354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson request1.setRequestMethod(requestMethod); 76454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, request1); 76554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 76654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection request2 = openConnection(url); 76854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (expectCached) { 7693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("1", request2.getHeaderField("X-Response-ID")); 77054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 77154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 77254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 77354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 77454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 77554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void postInvalidatesCache() throws Exception { 77654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("POST"); 77754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 77854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 77954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void putInvalidatesCache() throws Exception { 78054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("PUT"); 78154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 78254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 78354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void deleteMethodInvalidatesCache() throws Exception { 78454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("DELETE"); 78554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 78654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 78754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testMethodInvalidates(String requestMethod) throws Exception { 78854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache 78954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. invalidate it 79054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 3. expect a cache miss 79154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 79254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().setBody("A").addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 79354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 79454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 79554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 79654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 79754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 79854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 79954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 80054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 80154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection invalidate = openConnection(url); 80254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setRequestMethod(requestMethod); 80354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, invalidate); 80454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(invalidate)); 80554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 80654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(openConnection(url))); 80754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 80854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 809a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath @Test public void postInvalidatesCacheWithUncacheableResponse() throws Exception { 810a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 1. seed the cache 811a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 2. invalidate it with uncacheable response 812a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 3. expect a cache miss 813a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue( 814a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath new MockResponse().setBody("A").addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 815a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue(new MockResponse().setBody("B").setResponseCode(500)); 816a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue(new MockResponse().setBody("C")); 817a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.play(); 818a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 819a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath URL url = server.getUrl("/"); 820a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 821a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath assertEquals("A", readAscii(openConnection(url))); 822a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 823a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath HttpURLConnection invalidate = openConnection(url); 824a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath invalidate.setRequestMethod("POST"); 825a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath addRequestBodyIfNecessary("POST", invalidate); 826a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath assertEquals("B", readAscii(invalidate)); 827a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 828a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath assertEquals("C", readAscii(openConnection(url))); 829a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 830a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 83154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etag() throws Exception { 83254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = 83354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached(new MockResponse().addHeader("ETag: v1")); 83454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1")); 83554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 83654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 83754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInThePast() throws Exception { 83854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 83954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 84054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v1") 84154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 84254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 84354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 84454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-None-Match: v1")); 84554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 84654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 84754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 84854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInTheFuture() throws Exception { 84954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("ETag: v1") 85054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 85154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 85254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 85354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 85454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCache() throws Exception { 85554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 85654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 85754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 85854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 85954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 86054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 86154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 86254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 86354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-cache")); 86454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 86554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 86654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 86754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 86854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCache() throws Exception { 86954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 87054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 87154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 87254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 87354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 87454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 87554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 87654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 87754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Pragma: no-cache")); 87854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 87954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 88054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 88154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 88254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStore() throws Exception { 88354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 88454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 88554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 88654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 88754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 88854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 88954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-store")); 89054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 89154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 89254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void partialRangeResponsesDoNotCorruptCache() throws Exception { 89354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. request a range 89454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. request a full document, expecting a cache miss 89554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("AA") 89654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 89754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 89854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Range: bytes 1000-1001/2000")); 89954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("BB")); 90054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 90154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 90254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 90354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 90454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection range = openConnection(url); 90554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson range.addRequestProperty("Range", "bytes=1000-1001"); 90654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("AA", readAscii(range)); 90754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 90854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("BB", readAscii(openConnection(url))); 90954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 91054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 91154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverReturnsDocumentOlderThanCache() throws Exception { 91254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 91354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 91454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 91554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B") 91654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 91754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 91854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 91954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 92054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 92154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 92254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 92354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 92454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 92554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndConditionalCache() throws Exception { 92654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 92754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 92854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 92954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 93054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 93154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndFullCache() throws Exception { 93254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 93354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 93454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 93554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 93654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 93754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 93854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 93954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(gzip("ABCABCABC".getBytes("UTF-8"))).addHeader("Content-Encoding: gzip")); 94054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 941166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 94254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 94354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 944166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 945166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath // At least three request/response pairs are required because after the first request is cached 946166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath // a different execution path might be taken. Thus modifications to the cache applied during 947166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath // the second request might not be visible until another request is performed. 948166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 94954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 95054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 95154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 95254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 953166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath @Test public void notModifiedSpecifiesEncoding() throws Exception { 954166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 955166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .setBody(gzip("ABCABCABC".getBytes("UTF-8"))) 956166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Content-Encoding: gzip") 957166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 958166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 959166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 960166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED) 961166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Content-Encoding: gzip")); 962166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 963166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .setBody("DEFDEFDEF")); 964166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 965166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.play(); 966166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 967166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 968166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("DEFDEFDEF", readAscii(openConnection(server.getUrl("/")))); 969166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath } 970166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 971c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Test public void conditionalCacheHitIsNotDoublePooled() throws Exception { 972c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller server.enqueue(new MockResponse().addHeader("ETag: v1").setBody("A")); 973c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller server.enqueue(new MockResponse() 974c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller .clearHeaders() 975c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 976c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller server.play(); 977c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 978c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller ConnectionPool pool = ConnectionPool.getDefault(); 979c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller pool.evictAll(); 980c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller client.setConnectionPool(pool); 981c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 982c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 983c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 984c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller assertEquals(1, client.getConnectionPool().getConnectionCount()); 985c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 986c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 98754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expiresDateBeforeModifiedDate() throws Exception { 98854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached( 98954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 99054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 99154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 99254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 99354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxAge() throws IOException { 99454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 99554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 99654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 99754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 99854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 99954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 100054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 100154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 100254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 100354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 100454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-age=30"); 100554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 100654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 100754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 100854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMinFresh() throws IOException { 100954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 101054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 101154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 101254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 101354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 101454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 101554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 101654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 101754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 101854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 101954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 102054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 102154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 102254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStale() throws IOException { 102354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 102454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120") 102554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 102654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 102754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 102854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 102954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 103054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 103154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 103254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 103354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 103454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("110 HttpURLConnection \"Response is stale\"", 103554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 103654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 103754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 103854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStaleNotHonoredWithMustRevalidate() throws IOException { 103954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 104054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120, must-revalidate") 104154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 104254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 104354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 104454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 104554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 104654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 104754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 104854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 104954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 105054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 105154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 105254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithNoResponseCached() throws IOException { 105354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (no responses enqueued) 105454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 105554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 105654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 105754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 105854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 10593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getRequestCount()); 10603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getNetworkCount()); 10613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getHitCount()); 106254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 106354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 106454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithFullResponseCached() throws IOException { 106554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 106654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 106754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 106854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 106954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 107054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 107154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 107254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 1073faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 10743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(2, cache.getRequestCount()); 10753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getNetworkCount()); 10763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getHitCount()); 107754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 107854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 107954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithConditionalResponseCached() throws IOException { 108054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 108154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 108254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 108354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 108454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 108554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 108654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 108754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 108854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 10893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(2, cache.getRequestCount()); 10903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getNetworkCount()); 10913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getHitCount()); 109254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 109354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 109454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 109554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 109654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 109754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 109854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 109954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 110054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 110154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 11023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(2, cache.getRequestCount()); 11033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getNetworkCount()); 11043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getHitCount()); 110554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 110654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 110754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestCacheControlNoCache() throws Exception { 110854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 110954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 111054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 111154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 111254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 111354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 111454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 111554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 111654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 111754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 111854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 111954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Cache-Control", "no-cache"); 112054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 112154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 112254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 112354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestPragmaNoCache() throws Exception { 112454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 112554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 112654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 112754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 112854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 112954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 113054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 113154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 113254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 113354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 113454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 113554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Pragma", "no-cache"); 113654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 113754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 113854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 113954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 114054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 114154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v3").addHeader("Cache-Control: max-age=0"); 114254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 114354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = 114454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertClientSuppliedCondition(response, "If-Modified-Since", ifModifiedSinceDate); 114554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = request.getHeaders(); 114654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate)); 114754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(headers.contains("If-None-Match: v3")); 114854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 114954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 115054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 115154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 115254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 115354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 115454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0"); 115554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = assertClientSuppliedCondition(response, "If-None-Match", "v1"); 115654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = request.getHeaders(); 115754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-None-Match: v1")); 115854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate)); 115954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 116054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 116154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 116254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String conditionValue) throws Exception { 116354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(seed.setBody("A")); 116454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 116554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 116654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 116754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 116854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 116954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 117054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(url); 117154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty(conditionName, conditionValue); 117254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 117354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 117454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 117554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // seed 117654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); 117754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 117854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 11793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 11803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Confirm that {@link URLConnection#setIfModifiedSince} causes an 11813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * If-Modified-Since header with a GMT timestamp. 11823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 11833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * https://code.google.com/p/android/issues/detail?id=66135 11843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 118554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void setIfModifiedSince() throws Exception { 118654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 118754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 118854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 118954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 119054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 11913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller connection.setIfModifiedSince(1393666200000L); 119254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 119354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = server.takeRequest(); 11943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String ifModifiedSinceHeader = request.getHeader("If-Modified-Since"); 11953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("Sat, 01 Mar 2014 09:30:00 GMT", ifModifiedSinceHeader); 11963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 11973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 11983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 11993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * For Last-Modified and Date headers, we should echo the date back in the 12003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * exact format we were served. 12013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 12023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void retainServedDateFormat() throws Exception { 12033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Serve a response with a non-standard date format that OkHttp supports. 12043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Date lastModifiedDate = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(-1)); 12053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Date servedDate = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(-2)); 12063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller DateFormat dateFormat = new SimpleDateFormat("EEE dd-MMM-yyyy HH:mm:ss z", Locale.US); 12073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller dateFormat.setTimeZone(TimeZone.getTimeZone("EDT")); 12083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String lastModifiedString = dateFormat.format(lastModifiedDate); 12093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String servedString = dateFormat.format(servedDate); 12103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 12113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // This response should be conditionally cached. 12123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.enqueue(new MockResponse() 12133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .addHeader("Last-Modified: " + lastModifiedString) 12143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .addHeader("Expires: " + servedString) 12153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .setBody("A")); 12163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.enqueue(new MockResponse() 12173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 12183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.play(); 12193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 12203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 12213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 12223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 12233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // The first request has no conditions. 12243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller RecordedRequest request1 = server.takeRequest(); 12253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNull(request1.getHeader("If-Modified-Since")); 12263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 12273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // The 2nd request uses the server's date format. 12283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller RecordedRequest request2 = server.takeRequest(); 12293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(lastModifiedString, request2.getHeader("If-Modified-Since")); 123054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 123154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 123254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedConditionWithoutCachedResult() throws Exception { 123354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 123454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 123554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 123654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 123754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 123854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 123954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 124054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 124154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 124254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 124354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationRequestHeaderPreventsCaching() throws Exception { 124454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 124554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES)) 124654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 124754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 124854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 124954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 125054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 125154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 125254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 125354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Authorization", "password"); 125454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 125554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 125654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 125754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 125854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithSMaxAge() throws Exception { 125954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached( 126054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: s-maxage=60")); 126154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 126254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 126354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithPublic() throws Exception { 126454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached(new MockResponse().addHeader("Cache-Control: public")); 126554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 126654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 126754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithMustRevalidate() throws Exception { 126854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached( 126954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: must-revalidate")); 127054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 127154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 127254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception { 127354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.addHeader("Cache-Control: max-age=60").setBody("A")); 127454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 127554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 127654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 127754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 127854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 127954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Authorization", "password"); 128054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 128154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 128254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 128354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 128454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void contentLocationDoesNotPopulateCache() throws Exception { 128554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 128654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Location: /bar") 128754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 128854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 128954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 129054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 129154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/foo")))); 129254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/bar")))); 129354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 129454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 129554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotWriteToCache() throws Exception { 129654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 129754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 129854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 129954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 130054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 130154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 130254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 130354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 130454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 130554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 130654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 130754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotReadFromCache() throws Exception { 130854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 130954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 131054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 131154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 131254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 131354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 131454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 131554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 131654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 131754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 131854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 131954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultUseCachesSetsInitialValueOnly() throws Exception { 132054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = new URL("http://localhost/"); 132154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c1 = openConnection(url); 132254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c2 = openConnection(url); 132354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getDefaultUseCaches()); 132454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(false); 132554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 132654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getUseCaches()); 132754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c2.getUseCaches()); 132854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c3 = openConnection(url); 132954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(c3.getUseCaches()); 133054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 133154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(true); 133254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 133354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 133454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 133554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void connectionIsReturnedToPoolAfterConditionalSuccess() throws Exception { 133654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 133754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 133854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 133954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 134054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 134154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 134254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 134354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/a")))); 134454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/a")))); 134554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/b")))); 134654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 134754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, server.takeRequest().getSequenceNumber()); 134854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, server.takeRequest().getSequenceNumber()); 134954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.takeRequest().getSequenceNumber()); 135054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 135154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 135254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheMiss() throws Exception { 135354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 135454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 135554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 135654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 135754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 135854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 135954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 136054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 136154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 136254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 136354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 136454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 136554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(openConnection(server.getUrl("/")))); 136654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 136754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 136854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 136954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 137054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 137154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheHit() throws Exception { 137254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 137354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 137454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 137554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 137654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 137754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 137854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 137954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 138054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 138154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 138254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 138354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 138454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 138554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 138654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 138754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 138854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 138954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 139054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsFullCacheHit() throws Exception { 139154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A")); 139254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 139354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 139454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 139554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 139654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 139754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 139854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 139954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 140054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 140154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 140254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 140354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 140454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 140554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesChangedRequestHeaderField() throws Exception { 140654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 140754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 140854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 140954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 141054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 141154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 141254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 141354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection frConnection = openConnection(url); 141454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 141554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 141654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 141754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection enConnection = openConnection(url); 141854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-US"); 141954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 142054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 142154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 142254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesUnchangedRequestHeaderField() throws Exception { 142354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 142454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 142554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 142654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 142754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 142854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 142954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 143054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 143154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 143254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 143354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 143454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 143554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 143654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 143754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 143854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAbsentRequestHeaderField() throws Exception { 143954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 144054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 144154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 144254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 144354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 144454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 144554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 144654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 144754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 144854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 144954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAddedRequestHeaderField() throws Exception { 145054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 145154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 145254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 145354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 145454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 145554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 145654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 145754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection fooConnection = openConnection(server.getUrl("/")); 145854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 145954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(fooConnection)); 146054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 146154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 146254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesRemovedRequestHeaderField() throws Exception { 146354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 146454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 146554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 146654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 146754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 146854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 146954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection fooConnection = openConnection(server.getUrl("/")); 147054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 147154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(fooConnection)); 147254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 147354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 147454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 147554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyFieldsAreCaseInsensitive() throws Exception { 147654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 147754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: ACCEPT-LANGUAGE") 147854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 147954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 148054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 148154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 148254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 148354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 148454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 148554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 148654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 148754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("accept-language", "fr-CA"); 148854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 148954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 149054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 149154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithMatch() throws Exception { 149254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 149354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 149454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 149554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 149654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 149754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 149854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 149954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 150054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 150154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 150254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Charset", "UTF-8"); 150354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Encoding", "identity"); 150454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 150554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 150654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 150754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Charset", "UTF-8"); 150854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Encoding", "identity"); 150954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 151054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 151154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 151254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithNoMatch() throws Exception { 151354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 151454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 151554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 151654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 151754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 151854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 151954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 152054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 152154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection frConnection = openConnection(url); 152254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 152354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Charset", "UTF-8"); 152454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Encoding", "identity"); 152554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 152654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection enConnection = openConnection(url); 152754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-CA"); 152854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Charset", "UTF-8"); 152954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Encoding", "identity"); 153054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 153154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 153254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 153354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithMatch() throws Exception { 153454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 153554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 153654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 153754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 153854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 153954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 154054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 154154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 154254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 154354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 154454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 154554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 154654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 154754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 154854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 154954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 155054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 155154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 155254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithNoMatch() throws Exception { 155354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 155454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 155554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 155654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 155754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 155854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 155954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 156054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 156154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 156254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 156354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 156454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 156554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 156654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 156754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 156854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection2)); 156954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 157054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 157154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAsterisk() throws Exception { 157254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 157354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: *") 157454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 157554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 157654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 157754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 157854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 157954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 158054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 158154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 158254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAndHttps() throws Exception { 158354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 158454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 158554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 158654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 158754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 158854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 158954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 159054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 159154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(url); 159254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 159354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 159454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 159554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 159654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 159754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(url); 159854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setSSLSocketFactory(sslContext.getSocketFactory()); 159954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 160054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 160154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 160254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 160354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 160454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusCookies() throws Exception { 160554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 160654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";") 160754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 160854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 160954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 161054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 161154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";") 161254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 161354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 161454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 161554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 161654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 161754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=FIRST"); 161854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 161954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=SECOND"); 162054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 162154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 162254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsNetworkEndToEndHeaders() throws Exception { 162354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD") 162454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 162554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 162654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 162754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD, PUT") 162854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 162954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 163054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 163154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 163254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 163354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection1.getHeaderField("Allow")); 163454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 163554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 163654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 163754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD, PUT", connection2.getHeaderField("Allow")); 163854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 163954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 164054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsCachedHopByHopHeaders() throws Exception { 164154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: identity") 164254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 164354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 164454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 164554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: none") 164654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 164754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 164854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 164954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 165054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 165154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection1.getHeaderField("Transfer-Encoding")); 165254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 165354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 165454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 165554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection2.getHeaderField("Transfer-Encoding")); 165654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 165754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 165854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersDeletesCached100LevelWarnings() throws Exception { 165954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 199 test danger") 166054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 166154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 166254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 166354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 166454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 166554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 166654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 166754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 166854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("199 test danger", connection1.getHeaderField("Warning")); 166954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 167054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 167154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 167254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection2.getHeaderField("Warning")); 167354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 167454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 167554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersRetainsCached200LevelWarnings() throws Exception { 167654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 299 test danger") 167754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 167854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 167954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 168054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 168154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 168254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 168354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 168454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 168554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection1.getHeaderField("Warning")); 168654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 168754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 168854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 168954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection2.getHeaderField("Warning")); 169054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 169154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 169254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void assertCookies(URL url, String... expectedCookies) throws Exception { 169354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> actualCookies = new ArrayList<String>(); 169454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (HttpCookie cookie : cookieManager.getCookieStore().get(url.toURI())) { 169554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson actualCookies.add(cookie.toString()); 169654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 169754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList(expectedCookies), actualCookies); 169854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 169954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 170054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusRange() throws Exception { 170154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().setResponseCode(HttpURLConnection.HTTP_PARTIAL) 170254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 170354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Range: bytes 100-100/200") 170454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 170554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 170654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 170754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void conditionalHitUpdatesCache() throws Exception { 170854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS)) 170954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 171054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 171154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=30") 171254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Allow: GET, HEAD") 171354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 171454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 171554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 171654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 171754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // cache miss; seed the cache 171854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection1 = openConnection(server.getUrl("/a")); 171954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 172054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection1.getHeaderField("Allow")); 172154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 172254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // conditional cache hit; update the cache 172354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection2 = openConnection(server.getUrl("/a")); 172454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 172554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 172654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection2.getHeaderField("Allow")); 172754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 172854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // full cache hit 172954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection3 = openConnection(server.getUrl("/a")); 173054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection3)); 173154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection3.getHeaderField("Allow")); 173254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 173354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.getRequestCount()); 173454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 173554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1736faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderCached() throws IOException { 1737faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1738faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1739faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1740faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1741faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1742faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1743faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath URLConnection connection = openConnection(server.getUrl("/")); 1744faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath connection.addRequestProperty("Cache-Control", "only-if-cached"); 1745faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1746faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 17473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String source = connection.getHeaderField(OkHeaders.RESPONSE_SOURCE); 17483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(ResponseSource.CACHE + " 200", source); 1749faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1750faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1751faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheFetched() throws IOException { 1752faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1753faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1754faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(-31, TimeUnit.MINUTES))); 1755faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("B") 1756faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1757faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1758faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1759faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1760faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1761faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = openConnection(server.getUrl("/")); 1762faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("B", readAscii(connection)); 1763faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 17643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String source = connection.getHeaderField(OkHeaders.RESPONSE_SOURCE); 17653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(ResponseSource.CONDITIONAL_CACHE + " 200", source); 1766faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1767faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1768faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheNotFetched() throws IOException { 1769faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1770faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=0") 1771faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1772faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setResponseCode(304)); 1773faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1774faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1775faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1776faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = openConnection(server.getUrl("/")); 1777faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1778faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 17793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String source = connection.getHeaderField(OkHeaders.RESPONSE_SOURCE); 17803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(ResponseSource.CONDITIONAL_CACHE + " 304", source); 1781faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1782faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1783faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderFetched() throws IOException { 1784faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A")); 1785faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1786faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1787faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath URLConnection connection = openConnection(server.getUrl("/")); 1788faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1789faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 17903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String source = connection.getHeaderField(OkHeaders.RESPONSE_SOURCE); 17913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(ResponseSource.NETWORK + " 200", source); 1792faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1793faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1794faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void emptyResponseHeaderNameFromCacheIsLenient() throws Exception { 1795faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse() 1796faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=120") 1797faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader(": A") 1798faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .setBody("body")); 1799faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1800faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = client.open(server.getUrl("/")); 1801faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", connection.getHeaderField("")); 1802faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1803faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 180454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 1805166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * Old implementations of OkHttp's response cache wrote header fields like 1806166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * ":status: 200 OK". This broke our cached response parser because it split 1807166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * on the first colon. This regression test exists to help us read these old 1808166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * bad cache entries. 1809166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * 1810166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * https://github.com/square/okhttp/issues/227 1811166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath */ 1812166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath @Test public void testGoldenCacheResponse() throws Exception { 1813166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath cache.close(); 1814166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 1815166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .clearHeaders() 1816166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1817166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.play(); 1818166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 1819166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath URL url = server.getUrl("/"); 1820166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath String urlKey = Util.hash(url.toString()); 1821166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath String entryMetadata = "" 1822166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "" + url + "\n" 1823166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "GET\n" 1824166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "0\n" 1825166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "HTTP/1.1 200 OK\n" 1826166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "7\n" 1827166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + ":status: 200 OK\n" 1828166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + ":version: HTTP/1.1\n" 1829166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "etag: foo\n" 1830166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "content-length: 3\n" 1831166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "OkHttp-Received-Millis: " + System.currentTimeMillis() + "\n" 1832166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "X-Android-Response-Source: NETWORK 200\n" 1833166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "OkHttp-Sent-Millis: " + System.currentTimeMillis() + "\n" 1834166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "\n" 1835166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\n" 1836166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "1\n" 1837166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "MIIBpDCCAQ2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1qd2lsc29uLmxvY2FsMB4XDTEzMDgy" 1838166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "OTA1MDE1OVoXDTEzMDgzMDA1MDE1OVowGDEWMBQGA1UEAxMNandpbHNvbi5sb2NhbDCBnzANBgkqhkiG9w0BAQEF" 1839166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "AAOBjQAwgYkCgYEAlFW+rGo/YikCcRghOyKkJanmVmJSce/p2/jH1QvNIFKizZdh8AKNwojt3ywRWaDULA/RlCUc" 1840166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "ltF3HGNsCyjQI/+Lf40x7JpxXF8oim1E6EtDoYtGWAseelawus3IQ13nmo6nWzfyCA55KhAWf4VipelEy8DjcuFK" 1841166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "v6L0xwXnI0ECAwEAATANBgkqhkiG9w0BAQsFAAOBgQAuluNyPo1HksU3+Mr/PyRQIQS4BI7pRXN8mcejXmqyscdP" 1842166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "7S6J21FBFeRR8/XNjVOp4HT9uSc2hrRtTEHEZCmpyoxixbnM706ikTmC7SN/GgM+SmcoJ1ipJcNcl8N0X6zym4dm" 1843166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "yFfXKHu2PkTo7QFdpOJFvP3lIigcSZXozfmEDg==\n" 1844166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "-1\n"; 1845166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath String entryBody = "abc"; 1846166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath String journalBody = "" 1847166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "libcore.io.DiskLruCache\n" 1848166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "1\n" 1849166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "201105\n" 1850166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "2\n" 1851166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "\n" 1852166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "CLEAN " + urlKey + " " + entryMetadata.length() + " " + entryBody.length() + "\n"; 1853166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath writeFile(cache.getDirectory(), urlKey + ".0", entryMetadata); 1854166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath writeFile(cache.getDirectory(), urlKey + ".1", entryBody); 1855166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath writeFile(cache.getDirectory(), "journal", journalBody); 1856166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath cache = new HttpResponseCache(cache.getDirectory(), Integer.MAX_VALUE); 18573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller client.setOkResponseCache(cache); 1858166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 1859166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath HttpURLConnection connection = client.open(url); 1860166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals(entryBody, readAscii(connection)); 1861166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("3", connection.getHeaderField("Content-Length")); 1862166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("foo", connection.getHeaderField("etag")); 1863166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath } 1864166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 18654944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // Older versions of OkHttp use ResponseCache.get() and ResponseCache.put(). For compatibility 18664944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // with Android apps when the Android-bundled and and an older app-bundled OkHttp library are in 18674944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // use at the same time the HttpResponseCache must behave as it always used to. That's not the 18684944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // same as a fully API-compliant {@link ResponseCache}: That means that the cache 18694944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // doesn't throw an exception from get() or put() and also does not cache requests/responses from 18704944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // anything other than the variant of OkHttp that it comes with. It does still return values from 18714944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // get() and it is not expected to implement any cache-control logic. 18724944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller @Test public void testHttpResponseCacheBackwardsCompatible() throws Exception { 18734944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertSame(cache, ResponseCache.getDefault()); 18744944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(0, cache.getRequestCount()); 18754944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 18764944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller String body = "Body"; 18774944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller server.enqueue(new MockResponse() 18784944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 18794944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 18804944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller .setBody(body)); 18814944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller server.play(); 18824944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 18834944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller URL url = server.getUrl("/"); 18844944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 18854944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // Here we use a HttpURLConnection from URL to represent a non-OkHttp HttpURLConnection. In 18864944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // Android this would be com.android.okhttp.internal.http.HttpURLConnectionImpl. In tests this 18874944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // is some other implementation. 18884944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller HttpURLConnection javaConnection = (HttpURLConnection) url.openConnection(); 18894944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertFalse("This test relies on url.openConnection() not returning an OkHttp connection", 18904944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller javaConnection instanceof HttpURLConnectionImpl); 18914944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller javaConnection.disconnect(); 18924944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 18934944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // This should simply be discarded. It doesn't matter the connection is not useful. 18944944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller cache.put(url.toURI(), javaConnection); 18954944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 18964944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // Confirm the initial cache state. 18974944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertNull(cache.get(url.toURI(), "GET", new HashMap<String, List<String>>())); 18984944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 18994944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // Now cache a response 19004944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller HttpURLConnection okHttpConnection = openConnection(url); 19014944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(body, readAscii(okHttpConnection)); 19024944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller okHttpConnection.disconnect(); 19034944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 19044944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(1, server.getRequestCount()); 19054944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(0, cache.getHitCount()); 19064944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 19074944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // OkHttp should now find the result cached. 19084944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller HttpURLConnection okHttpConnection2 = openConnection(url); 19094944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(body, readAscii(okHttpConnection2)); 19104944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller okHttpConnection2.disconnect(); 19114944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 19124944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(1, server.getRequestCount()); 19134944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(1, cache.getHitCount()); 19144944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 19154944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // Confirm the unfortunate get() behavior. 19164944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertNotNull(cache.get(url.toURI(), "GET", new HashMap<String, List<String>>())); 19174944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller // Only OkHttp makes the necessary callbacks to increment the cache stats. 19184944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller assertEquals(1, cache.getHitCount()); 19194944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller } 19204944713f5c5b141966ac82973d6a31a634e8e01eNeil Fuller 1921166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath private void writeFile(File directory, String file, String content) throws IOException { 1922166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath OutputStream out = new FileOutputStream(new File(directory, file)); 1923166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath out.write(content.getBytes(Util.UTF_8)); 1924166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath out.close(); 1925166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath } 1926166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 1927166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath /** 192854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * @param delta the offset from the current date to use. Negative 192954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * values yield dates in the past; positive values yield dates in the 193054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * future. 193154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 193254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(long delta, TimeUnit timeUnit) { 193354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta))); 193454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 193554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 193654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(Date date) { 193754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 1938166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath rfc1123.setTimeZone(TimeZone.getTimeZone("GMT")); 193954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return rfc1123.format(date); 194054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 194154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 194254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 194354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 194454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 194554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setDoOutput(true); 194654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream requestBody = invalidate.getOutputStream(); 194754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.write('x'); 194854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.close(); 194954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 195054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 195154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 195254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNotCached(MockResponse response) throws Exception { 195354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 195454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 195554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 195654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 195754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 195854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 195954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 196054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 196154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 196254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** @return the request with the conditional get headers. */ 196354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 196454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // scenario 1: condition succeeds 196554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A").setStatus("HTTP/1.1 200 A-OK")); 196654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 196754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 196854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // scenario 2: condition fails 196954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("B").setStatus("HTTP/1.1 200 B-OK")); 197054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 C-OK").setBody("C")); 197154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 197254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 197354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 197454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL valid = server.getUrl("/valid"); 197554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection1 = openConnection(valid); 197654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 197754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection1.getResponseCode()); 197854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection1.getResponseMessage()); 197954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection2 = openConnection(valid); 198054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 198154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 198254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection2.getResponseMessage()); 198354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 198454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL invalid = server.getUrl("/invalid"); 198554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection3 = openConnection(invalid); 198654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection3)); 198754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection3.getResponseCode()); 198854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B-OK", connection3.getResponseMessage()); 198954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection4 = openConnection(invalid); 199054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(connection4)); 199154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection4.getResponseCode()); 199254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C-OK", connection4.getResponseMessage()); 199354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 199454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // regular get 199554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); // conditional get 199654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 199754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 199854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertFullyCached(MockResponse response) throws Exception { 199954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 200054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("B")); 200154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 200254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 200354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 200454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 200554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 200654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 200754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 200854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 200954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Shortens the body of {@code response} but not the corresponding headers. 201054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Only useful to test how clients respond to the premature conclusion of 201154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * the HTTP body. 201254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 201354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 201454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setSocketPolicy(DISCONNECT_AT_END); 201554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = new ArrayList<String>(response.getHeaders()); 201654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 201754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.getHeaders().clear(); 201854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.getHeaders().addAll(headers); 201954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response; 202054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 202154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 202254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 202354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Reads {@code count} characters from the stream. If the stream is 202454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * exhausted before {@code count} characters can be read, the remaining 202554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * characters are returned and the stream is closed. 202654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 202754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection, int count) throws IOException { 202854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 202954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 20303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? connection.getInputStream() 20313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : httpConnection.getErrorStream(); 203254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson StringBuilder result = new StringBuilder(); 203354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 0; i < count; i++) { 203454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int value = in.read(); 203554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (value == -1) { 20367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath in.close(); 203754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 203854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 203954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson result.append((char) value); 204054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 204154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return result.toString(); 204254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 204354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 204454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection) throws IOException { 204554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return readAscii(connection, Integer.MAX_VALUE); 204654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 204754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 204854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void reliableSkip(InputStream in, int length) throws IOException { 204954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson while (length > 0) { 205054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson length -= in.skip(length); 205154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 205254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 205354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 205454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertGatewayTimeout(HttpURLConnection connection) throws IOException { 205554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 205654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getInputStream(); 205754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 205854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (FileNotFoundException expected) { 205954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 206054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(504, connection.getResponseCode()); 206154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, connection.getErrorStream().read()); 20623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(ResponseSource.NONE + " 504", 20633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller connection.getHeaderField(OkHeaders.RESPONSE_SOURCE)); 206454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 206554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 206654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enum TransferKind { 206754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CHUNKED() { 206854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) 206954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 207054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setChunkedBody(content, chunkSize); 207154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 207254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 207354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson FIXED_LENGTH() { 207454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 207554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 207654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 207754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 207854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson END_OF_STREAM() { 207954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 208054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 20817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath response.setSocketPolicy(DISCONNECT_AT_END); 208254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 208354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (h.next().startsWith("Content-Length:")) { 208454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson h.remove(); 208554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 208654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 20877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 208854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 208954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 20907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 209154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson abstract void setBody(MockResponse response, byte[] content, int chunkSize) throws IOException; 209254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 209354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 209454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setBody(response, content.getBytes("UTF-8"), chunkSize); 209554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 209654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 209754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 209854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 209954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 210054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 210154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 210254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns a gzipped copy of {@code bytes}. */ 210354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public byte[] gzip(byte[] bytes) throws IOException { 210454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 210554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 210654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson gzippedOut.write(bytes); 210754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson gzippedOut.close(); 210854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return bytesOut.toByteArray(); 210954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 211054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller static abstract class AbstractOkResponseCache implements OkResponseCache { 21123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public Response get(Request request) throws IOException { 21133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; 211454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 211554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public CacheRequest put(Response response) throws IOException { 21173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return null; 21183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 21193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 21203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public boolean maybeRemove(Request request) throws IOException { 21213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return false; 21223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 21233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 21243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void update(Response cached, Response network) throws IOException { 21253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 21263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 21273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void trackConditionalCacheHit() { 21283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 21293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 21303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public void trackResponse(ResponseSource source) { 21317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 213254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 21337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath} 2134