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 197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.MockResponse; 207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.MockWebServer; 217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.RecordedRequest; 22faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport com.squareup.okhttp.HttpResponseCache; 232231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.OkHttpClient; 24faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport com.squareup.okhttp.ResponseSource; 252231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.SslContextBuilder; 267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.BufferedReader; 277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.ByteArrayOutputStream; 287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.File; 297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.FileNotFoundException; 307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.IOException; 317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStream; 327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStreamReader; 337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.OutputStream; 347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CacheRequest; 357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CacheResponse; 367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieHandler; 377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieManager; 387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpCookie; 397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpURLConnection; 402231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.InetAddress; 417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.ResponseCache; 427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.SecureCacheResponse; 437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URI; 447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URISyntaxException; 457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URL; 467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URLConnection; 472231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.UnknownHostException; 482231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.GeneralSecurityException; 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.Collections; 567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Date; 577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Iterator; 587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.List; 597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Locale; 607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Map; 617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.TimeZone; 627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.UUID; 637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.TimeUnit; 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 7554cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport static com.google.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; 802231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertTrue; 812231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.fail; 827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 8354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson/** Android's HttpResponseCacheTest. */ 842231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpublic final class HttpResponseCacheTest { 8554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final HostnameVerifier NULL_HOSTNAME_VERIFIER = new HostnameVerifier() { 8654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public boolean verify(String s, SSLSession sslSession) { 8754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return true; 8854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 8954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 9054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final OkHttpClient client = new OkHttpClient(); 9154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private MockWebServer server = new MockWebServer(); 9274623587bf099735cf16ec2298005f12fd3fcb07jwilson private MockWebServer server2 = new MockWebServer(); 9354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private HttpResponseCache cache; 9454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final CookieManager cookieManager = new CookieManager(); 9554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 9654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final SSLContext sslContext; 9754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson static { 9854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 9954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson sslContext = new SslContextBuilder(InetAddress.getLocalHost().getHostName()).build(); 10054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (GeneralSecurityException e) { 10154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 10254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (UnknownHostException e) { 10354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 10454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 10554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 10654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 10754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Before public void setUp() throws Exception { 10854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String tmp = System.getProperty("java.io.tmpdir"); 10954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); 11054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE); 11154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(cache); 11254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(cookieManager); 11354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 11454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 11554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @After public void tearDown() throws Exception { 11654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.shutdown(); 11774623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.shutdown(); 11854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(null); 119faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath cache.delete(); 12054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(null); 12154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 12254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 12354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private HttpURLConnection openConnection(URL url) { 12454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return client.open(url); 12554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 12654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 12754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 12854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Test that response caching is consistent with the RI and the spec. 12954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 13054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 13154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingByResponseCode() throws Exception { 13254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Test each documented HTTP/1.1 code, plus the first unused value in each range. 13354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 13454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 13554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We can't test 100 because it's not really a response. 13654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // assertCached(false, 100); 13754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 101); 13854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 102); 13954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 200); 14054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 201); 14154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 202); 14254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 203); 14354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 204); 14454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 205); 14554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 206); // we don't cache partial responses 14654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 207); 14754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 300); 14854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 301); 14954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 302; i <= 308; ++i) { 15054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 15154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 15254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 400; i <= 406; ++i) { 15354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 15454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 15554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (See test_responseCaching_407.) 15654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 408); 15754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 409); 15854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (See test_responseCaching_410.) 15954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 411; i <= 418; ++i) { 16054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 16154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 500; i <= 506; ++i) { 16354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 16454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 16754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 16854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Response code 407 should only come from proxy servers. Android's client 16954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * throws if it is sent by an origin server. 17054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 17154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void originServerSends407() throws Exception { 17254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(407)); 17354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 17554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection conn = openConnection(url); 17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 17854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson conn.getResponseCode(); 17954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 18054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 18454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCaching_410() throws Exception { 18554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // the HTTP spec permits caching 410s, but the RI doesn't. 18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 410); 18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertCached(boolean shouldPut, int responseCode) throws Exception { 19054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server = new MockWebServer(); 19154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 19254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 19354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 19454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(responseCode) 19554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABCDE") 19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("WWW-Authenticate: challenge"); 19754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) { 19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("Proxy-Authenticate: Basic realm=\"protected area\""); 19954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { 20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("WWW-Authenticate: Basic realm=\"protected area\""); 20154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 20354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 20554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 20654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection conn = openConnection(url); 20754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(responseCode, conn.getResponseCode()); 20854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 20954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // exhaust the content stream 21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(conn); 21154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CacheResponse cached = 21354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cache.get(url.toURI(), "GET", Collections.<String, List<String>>emptyMap()); 21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (shouldPut) { 21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotNull(Integer.toString(responseCode), cached); 21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cached.getBody().close(); 21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(Integer.toString(responseCode), cached); 21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 22354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 22454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Test that we can interrogate the response when the cache is being 22554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * populated. http://code.google.com/p/android/issues/detail?id=7787 22654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 22754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCacheCallbackApis() throws Exception { 22854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final String body = "ABCDE"; 22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final AtomicInteger cacheCount = new AtomicInteger(); 23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 23254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().setStatus("HTTP/1.1 200 Fantastic").addHeader("fgh: ijk").setBody(body)); 23354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 23454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(new ResponseCache() { 23654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheResponse get(URI uri, String requestMethod, 23754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Map<String, List<String>> requestHeaders) throws IOException { 23854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 23954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 24074623587bf099735cf16ec2298005f12fd3fcb07jwilson 24154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 24254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection httpConnection = (HttpURLConnection) conn; 2432231db3e6bb54447a9b14cf004a6cb03c373651cjwilson try { 24454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.getRequestProperties(); 24554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 24654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalStateException expected) { 2477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 2487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath try { 24954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.addRequestProperty("K", "V"); 25054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 25154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalStateException expected) { 2527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 25354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("HTTP/1.1 200 Fantastic", httpConnection.getHeaderField(null)); 25454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), 25554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.getHeaderFields().get(null)); 25654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(200, httpConnection.getResponseCode()); 25754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Fantastic", httpConnection.getResponseMessage()); 25854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(body.length(), httpConnection.getContentLength()); 25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ijk", httpConnection.getHeaderField("fgh")); 2607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath try { 26154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.getInputStream(); // the RI doesn't forbid this, but it should 26254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 2637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } catch (IOException expected) { 2647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 26554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cacheCount.incrementAndGet(); 26654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 26754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 26854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }); 26954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 27054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 27154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(url); 27254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(body, readAscii(connection)); 27354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cacheCount.get()); 27454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 27554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 27654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithFixedLength() throws IOException { 27754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.FIXED_LENGTH); 27854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 27954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 28054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 28154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.CHUNKED); 28254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 28354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 28454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 28554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.END_OF_STREAM); 28654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 28754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 28854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 28954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 29054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://code.google.com/p/android/issues/detail?id=8175 29154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 29254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testResponseCaching(TransferKind transferKind) throws IOException { 29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 29554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setStatus("HTTP/1.1 200 Fantastic"); 29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 29854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 30054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Make sure that calling skip() doesn't omit bytes from the cache. 30254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection urlConnection = openConnection(server.getUrl("/")); 30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = urlConnection.getInputStream(); 30454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love ", readAscii(urlConnection, "I love ".length())); 30554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reliableSkip(in, "puppies but hate ".length()); 30654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("spiders", readAscii(urlConnection, "spiders".length())); 30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 30854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 30954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 31054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson urlConnection = openConnection(server.getUrl("/")); // cached! 31354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in = urlConnection.getInputStream(); 31454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love puppies but hate spiders", 31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(urlConnection, "I love puppies but hate spiders".length())); 31654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(200, urlConnection.getResponseCode()); 31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 31854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 31954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 32054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 32154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 32254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 32354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 32454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 32554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 32654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 32754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCaching() throws IOException { 32854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 32954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 33054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 33154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 33254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 33354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 33454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection = (HttpsURLConnection) client.open(server.getUrl("/")); 33554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setSSLSocketFactory(sslContext.getSocketFactory()); 33654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 33754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 33854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 33954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 34054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String suite = connection.getCipherSuite(); 34154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<Certificate> localCerts = toListOrNull(connection.getLocalCertificates()); 34254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<Certificate> serverCerts = toListOrNull(connection.getServerCertificates()); 34354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Principal peerPrincipal = connection.getPeerPrincipal(); 34454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Principal localPrincipal = connection.getLocalPrincipal(); 34554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 34654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = (HttpsURLConnection) client.open(server.getUrl("/")); // cached! 34754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setSSLSocketFactory(sslContext.getSocketFactory()); 34854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 34954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 35054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 35154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 35254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 35354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 35454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 35554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(suite, connection.getCipherSuite()); 35654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(localCerts, toListOrNull(connection.getLocalCertificates())); 35754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(serverCerts, toListOrNull(connection.getServerCertificates())); 35854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(peerPrincipal, connection.getPeerPrincipal()); 35954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(localPrincipal, connection.getLocalPrincipal()); 36054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 36154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 36254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheReturnsInsecureResponseForSecureRequest() throws IOException { 36354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 36454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("ABC")); 36554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 36654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 36754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 36854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(new InsecureResponseCache()); 36954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 37054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(server.getUrl("/")); 37154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 37254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 37354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection1)); 37454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 37554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Not cached! 37654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(server.getUrl("/")); 37754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setSSLSocketFactory(sslContext.getSocketFactory()); 37854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 37954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("DEF", readAscii(connection2)); 38054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 38154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 38254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndRedirects() throws Exception { 38354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 38454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 38554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 38654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 38754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 38854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 38954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 39054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 39154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 39254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 39454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 39554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = openConnection(server.getUrl("/")); // cached! 39754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 39854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects 40054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getNetworkCount()); 40154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 40254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 40354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 40454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void redirectToCachedResult() throws Exception { 40554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("ABC")); 40654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 40754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 40854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 40954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 41054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 41154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(openConnection(server.getUrl("/foo")))); 41254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request1 = server.takeRequest(); 41354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /foo HTTP/1.1", request1.getRequestLine()); 41454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, request1.getSequenceNumber()); 41554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 41654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(openConnection(server.getUrl("/bar")))); 41754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request2 = server.takeRequest(); 41854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /bar HTTP/1.1", request2.getRequestLine()); 41954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, request2.getSequenceNumber()); 42054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 42154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // an unrelated request should reuse the pooled connection 42254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("DEF", readAscii(openConnection(server.getUrl("/baz")))); 42354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request3 = server.takeRequest(); 42454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /baz HTTP/1.1", request3.getRequestLine()); 42554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, request3.getSequenceNumber()); 42654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 42754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 42854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCachingAndRedirects() throws IOException { 42954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 43054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 43154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 43254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 43354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 43454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 43554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 43654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 43754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 43854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 43954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 44054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(server.getUrl("/")); 44154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 44254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 44354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection1)); 44454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 44554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Cached! 44654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(server.getUrl("/")); 44754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 44854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 44954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection2)); 45054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 45154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 45254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 45374623587bf099735cf16ec2298005f12fd3fcb07jwilson } 45474623587bf099735cf16ec2298005f12fd3fcb07jwilson 45574623587bf099735cf16ec2298005f12fd3fcb07jwilson /** 45674623587bf099735cf16ec2298005f12fd3fcb07jwilson * We've had bugs where caching and cross-protocol redirects yield class 45774623587bf099735cf16ec2298005f12fd3fcb07jwilson * cast exceptions internal to the cache because we incorrectly assumed that 45874623587bf099735cf16ec2298005f12fd3fcb07jwilson * HttpsURLConnection was always HTTPS and HttpURLConnection was always HTTP; 45974623587bf099735cf16ec2298005f12fd3fcb07jwilson * in practice redirects mean that each can do either. 46074623587bf099735cf16ec2298005f12fd3fcb07jwilson * 46174623587bf099735cf16ec2298005f12fd3fcb07jwilson * https://github.com/square/okhttp/issues/214 46274623587bf099735cf16ec2298005f12fd3fcb07jwilson */ 46374623587bf099735cf16ec2298005f12fd3fcb07jwilson @Test public void secureResponseCachingAndProtocolRedirects() throws IOException { 46474623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.useHttps(sslContext.getSocketFactory(), false); 46574623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 46674623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 46774623587bf099735cf16ec2298005f12fd3fcb07jwilson .setBody("ABC")); 46874623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.enqueue(new MockResponse().setBody("DEF")); 46974623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.play(); 47074623587bf099735cf16ec2298005f12fd3fcb07jwilson 47174623587bf099735cf16ec2298005f12fd3fcb07jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 47274623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 47374623587bf099735cf16ec2298005f12fd3fcb07jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 47474623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Location: " + server2.getUrl("/"))); 47574623587bf099735cf16ec2298005f12fd3fcb07jwilson server.play(); 47674623587bf099735cf16ec2298005f12fd3fcb07jwilson 47774623587bf099735cf16ec2298005f12fd3fcb07jwilson client.setSslSocketFactory(sslContext.getSocketFactory()); 47874623587bf099735cf16ec2298005f12fd3fcb07jwilson client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 47974623587bf099735cf16ec2298005f12fd3fcb07jwilson 48074623587bf099735cf16ec2298005f12fd3fcb07jwilson HttpURLConnection connection1 = client.open(server.getUrl("/")); 48174623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals("ABC", readAscii(connection1)); 48274623587bf099735cf16ec2298005f12fd3fcb07jwilson 48374623587bf099735cf16ec2298005f12fd3fcb07jwilson // Cached! 48474623587bf099735cf16ec2298005f12fd3fcb07jwilson HttpURLConnection connection2 = client.open(server.getUrl("/")); 48574623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals("ABC", readAscii(connection2)); 48674623587bf099735cf16ec2298005f12fd3fcb07jwilson 48774623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 48874623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals(2, cache.getHitCount()); 48954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 49054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 49154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCacheRequestHeaders() throws IOException, URISyntaxException { 49254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("ABC")); 49354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 49454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 49554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final AtomicReference<Map<String, List<String>>> requestHeadersRef = 49654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new AtomicReference<Map<String, List<String>>>(); 49754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(new ResponseCache() { 49854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheResponse get(URI uri, String requestMethod, 49954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Map<String, List<String>> requestHeaders) throws IOException { 50054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestHeadersRef.set(requestHeaders); 50154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 50254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 50354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 50454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 50554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 50654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }); 50754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 50854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 50954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection urlConnection = openConnection(url); 51054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson urlConnection.addRequestProperty("A", "android"); 51154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(urlConnection); 51254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList("android"), requestHeadersRef.get().get("A")); 51354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 51454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 51554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 51654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 51754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 51854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 51954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 52054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.CHUNKED); 52154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 52254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 52454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Intentionally empty. This case doesn't make sense because there's no 52554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // such thing as a premature disconnect when the disconnect itself 52654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // indicates the end of the data stream. 52754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 52854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 53054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse(); 53154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 53254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(truncateViolently(response, 16)); 53354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 53454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 53554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 53654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson BufferedReader reader = new BufferedReader( 53754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new InputStreamReader(openConnection(server.getUrl("/")).getInputStream())); 53854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", reader.readLine()); 53954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 54054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.readLine(); 54154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("This implementation silently ignored a truncated HTTP body."); 54254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 54354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 54454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.close(); 54554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 54654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 54754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 54854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 54954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 55054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 55154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 55254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 55354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 55454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 55554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithContentLengthHeader() throws IOException { 55654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 55754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 55854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 55954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithChunkedEncoding() throws IOException { 56054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.CHUNKED); 56154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 56254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 56354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithNoLengthHeaders() throws IOException { 56454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 56554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 56654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 56754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 56854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Setting a low transfer speed ensures that stream discarding will time out. 56954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse().setBytesPerSecond(6); 57054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 57154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 57254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 57354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 57454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 57554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 57654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = connection.getInputStream(); 57754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", readAscii(connection, 5)); 57854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 57954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 58054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.read(); 58154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("Expected an IOException because the stream is closed."); 58254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 58354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 58454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 58554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 58654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 58754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = openConnection(server.getUrl("/")); 58854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 58954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 59054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 59154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 59254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 59354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 59454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 seconds ago 59554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 seconds ago 59654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 seconds 59754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds from now 59854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 59954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 60054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 60154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 60254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 60354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 60454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 60554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 60654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 60754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 60854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(connection.getHeaderField("Warning")); 60954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 61054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 61154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateConditionallyCached() throws Exception { 61254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 115 seconds ago 61354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 15 seconds ago 61454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (115 - 15) / 10 = 10 seconds 61554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds ago 61654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 61754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 61854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 61954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 62054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 62154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 62254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 62354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 62454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 62554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 days ago 62654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 days ago 62754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 days 62854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 days from served date = 5 days from now 62954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 63054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 63154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 63254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 63354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 63454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 63554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 63654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 63754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 63854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 63954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 64054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 64154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void noDefaultExpirationForUrlsWithQueryString() throws Exception { 64254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 64354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 64454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 64554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 64654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 64754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 64854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 64954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/?foo=bar"); 65054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 65154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 65254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 65354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 65454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithLastModifiedHeader() throws Exception { 65554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 65654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 65754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 65854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 65954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 66054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 66154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 66254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 66354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithNoLastModifiedHeader() throws Exception { 66454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 66554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 66654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 66754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInTheFuture() throws Exception { 66854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 66954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 67054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 67154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredWithMaxAgeAndExpires() throws Exception { 67254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 67354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 67454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 67554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 67654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 67754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 67854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 67954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 68054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 68154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 68254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 68354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 68454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 68554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 68654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 68754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 68854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Chrome interprets max-age relative to the local clock. Both our cache 68954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // and Firefox both use the earlier of the local and server's clock. 69054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 69154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 69254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 69354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 69454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateHeader() throws Exception { 69554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 69654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 69754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 69854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 69954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithNoDateHeader() throws Exception { 70054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Cache-Control: max-age=60")); 70154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 70254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 70354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeWithLastModifiedButNoServedDate() throws Exception { 70454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 70554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 70654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 70754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 70854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 70954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 71054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 71154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 71254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 71354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 71454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 71554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 71654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverLowerSharedMaxAge() throws Exception { 71754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 71854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=60") 71954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=180")); 72054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 72154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverHigherMaxAge() throws Exception { 72354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 72454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=180") 72554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 72654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 72754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodOptionsIsNotCached() throws Exception { 72954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("OPTIONS", false); 73054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 73154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 73254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodGetIsCached() throws Exception { 73354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("GET", true); 73454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 73554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 73654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodHeadIsNotCached() throws Exception { 73754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 73854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("HEAD", false); 73954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPostIsNotCached() throws Exception { 74254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 74354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("POST", false); 74454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPutIsNotCached() throws Exception { 74754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("PUT", false); 74854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodDeleteIsNotCached() throws Exception { 75154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("DELETE", false); 75254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 75354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodTraceIsNotCached() throws Exception { 75554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("TRACE", false); 75654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 75754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 75954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache (potentially) 76054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. expect a cache hit or miss 76154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 76254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("X-Response-ID: 1")); 76354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("X-Response-ID: 2")); 76454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 76554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 76754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection request1 = openConnection(url); 76954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson request1.setRequestMethod(requestMethod); 77054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, request1); 77154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 77254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 77354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection request2 = openConnection(url); 77454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (expectCached) { 77554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 77654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 77754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 77854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 77954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 78054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 78154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void postInvalidatesCache() throws Exception { 78254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("POST"); 78354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 78454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 78554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void putInvalidatesCache() throws Exception { 78654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("PUT"); 78754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 78854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 78954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void deleteMethodInvalidatesCache() throws Exception { 79054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("DELETE"); 79154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 79254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 79354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testMethodInvalidates(String requestMethod) throws Exception { 79454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache 79554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. invalidate it 79654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 3. expect a cache miss 79754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 79854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().setBody("A").addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 79954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 80054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 80154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 80254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 80354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 80454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 80554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 80654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 80754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection invalidate = openConnection(url); 80854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setRequestMethod(requestMethod); 80954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, invalidate); 81054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(invalidate)); 81154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 81254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(openConnection(url))); 81354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 81454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 815a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath @Test public void postInvalidatesCacheWithUncacheableResponse() throws Exception { 816a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 1. seed the cache 817a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 2. invalidate it with uncacheable response 818a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 3. expect a cache miss 819a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue( 820a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath new MockResponse().setBody("A").addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 821a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue(new MockResponse().setBody("B").setResponseCode(500)); 822a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue(new MockResponse().setBody("C")); 823a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.play(); 824a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 825a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath URL url = server.getUrl("/"); 826a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 827a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath assertEquals("A", readAscii(openConnection(url))); 828a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 829a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath HttpURLConnection invalidate = openConnection(url); 830a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath invalidate.setRequestMethod("POST"); 831a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath addRequestBodyIfNecessary("POST", invalidate); 832a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath assertEquals("B", readAscii(invalidate)); 833a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 834a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath assertEquals("C", readAscii(openConnection(url))); 835a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 836a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 83754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etag() throws Exception { 83854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = 83954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached(new MockResponse().addHeader("ETag: v1")); 84054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1")); 84154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 84254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 84354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInThePast() throws Exception { 84454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 84554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 84654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v1") 84754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 84854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 84954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 85054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-None-Match: v1")); 85154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 85254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 85354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 85454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInTheFuture() throws Exception { 85554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("ETag: v1") 85654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 85754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 85854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 85954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 86054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCache() throws Exception { 86154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 86254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 86354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 86454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 86554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 86654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 86754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 86854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 86954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-cache")); 87054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 87154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 87254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 87354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 87454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCache() throws Exception { 87554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 87654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 87754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 87854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 87954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 88054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 88154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 88254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 88354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Pragma: no-cache")); 88454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 88554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 88654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 88754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 88854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStore() throws Exception { 88954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 89054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 89154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 89254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 89354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 89454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 89554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-store")); 89654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 89754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 89854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void partialRangeResponsesDoNotCorruptCache() throws Exception { 89954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. request a range 90054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. request a full document, expecting a cache miss 90154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("AA") 90254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 90354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 90454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Range: bytes 1000-1001/2000")); 90554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("BB")); 90654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 90754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 90854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 90954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 91054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection range = openConnection(url); 91154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson range.addRequestProperty("Range", "bytes=1000-1001"); 91254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("AA", readAscii(range)); 91354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 91454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("BB", readAscii(openConnection(url))); 91554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 91654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 91754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverReturnsDocumentOlderThanCache() throws Exception { 91854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 91954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 92054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 92154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B") 92254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 92354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 92454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 92554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 92654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 92754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 92854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 92954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 93054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 93154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndConditionalCache() throws Exception { 93254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 93354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 93454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 93554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 93654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 93754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndFullCache() throws Exception { 93854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 93954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 94054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 94154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 94254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 94354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 94454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 94554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(gzip("ABCABCABC".getBytes("UTF-8"))).addHeader("Content-Encoding: gzip")); 94654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 94754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 94854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 94954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 95054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 95154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 95254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 95354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expiresDateBeforeModifiedDate() throws Exception { 95454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached( 95554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 95654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 95754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 95854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 95954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxAge() throws IOException { 96054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 96154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 96254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 96354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 96454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 96554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 96654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 96754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 96854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 96954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 97054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-age=30"); 97154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 97254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 97354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 97454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMinFresh() throws IOException { 97554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 97654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 97754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 97854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 97954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 98054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 98154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 98254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 98354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 98454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 98554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 98654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 98754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 98854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStale() throws IOException { 98954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 99054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120") 99154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 99254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 99354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 99454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 99554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 99654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 99754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 99854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 99954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 100054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("110 HttpURLConnection \"Response is stale\"", 100154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 100254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 100354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 100454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStaleNotHonoredWithMustRevalidate() throws IOException { 100554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 100654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120, must-revalidate") 100754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 100854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 100954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 101054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 101154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 101254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 101354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 101454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 101554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 101654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 101754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 101854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithNoResponseCached() throws IOException { 101954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (no responses enqueued) 102054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 102154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 102254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 102354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 102454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 102554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 102654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 102754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithFullResponseCached() throws IOException { 102854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 102954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 103054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 103154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 103254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 103354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 103454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 103554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 1036faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 103754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 103854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 103954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithConditionalResponseCached() throws IOException { 104054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 104154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 104254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 104354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 104454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 104554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 104654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 104754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 104854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 104954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 105054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 105154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 105254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 105354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 105454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 105554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 105654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 105754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 105854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 105954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 106054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 106154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestCacheControlNoCache() throws Exception { 106254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 106354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 106454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 106554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 106654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 106754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 106854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 106954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 107054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 107154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 107254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 107354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Cache-Control", "no-cache"); 107454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 107554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 107654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 107754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestPragmaNoCache() throws Exception { 107854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 107954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 108054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 108154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 108254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 108354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 108454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 108554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 108654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 108754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 108854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 108954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Pragma", "no-cache"); 109054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 109154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 109254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 109354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 109454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 109554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v3").addHeader("Cache-Control: max-age=0"); 109654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 109754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = 109854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertClientSuppliedCondition(response, "If-Modified-Since", ifModifiedSinceDate); 109954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = request.getHeaders(); 110054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate)); 110154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(headers.contains("If-None-Match: v3")); 110254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 110354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 110454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 110554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 110654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 110754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 110854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0"); 110954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = assertClientSuppliedCondition(response, "If-None-Match", "v1"); 111054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = request.getHeaders(); 111154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-None-Match: v1")); 111254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate)); 111354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 111454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 111554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 111654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String conditionValue) throws Exception { 111754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(seed.setBody("A")); 111854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 111954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 112054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 112154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 112254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 112354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 112454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(url); 112554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty(conditionName, conditionValue); 112654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 112754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 112854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 112954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // seed 113054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); 113154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 113254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 113354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void setIfModifiedSince() throws Exception { 113454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Date since = new Date(); 113554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 113654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 113754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 113854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 113954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 114054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setIfModifiedSince(since.getTime()); 114154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 114254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = server.takeRequest(); 114354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(request.getHeaders().contains("If-Modified-Since: " + formatDate(since))); 114454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 114554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 114654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedConditionWithoutCachedResult() throws Exception { 114754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 114854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 114954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 115054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 115154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 115254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 115354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 115454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 115554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 115654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 115754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationRequestHeaderPreventsCaching() throws Exception { 115854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 115954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES)) 116054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 116154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 116254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 116354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 116454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 116554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 116654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 116754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Authorization", "password"); 116854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 116954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 117054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 117154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 117254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithSMaxAge() throws Exception { 117354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached( 117454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: s-maxage=60")); 117554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 117654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 117754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithPublic() throws Exception { 117854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached(new MockResponse().addHeader("Cache-Control: public")); 117954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 118054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 118154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithMustRevalidate() throws Exception { 118254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached( 118354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: must-revalidate")); 118454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 118554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 118654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception { 118754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.addHeader("Cache-Control: max-age=60").setBody("A")); 118854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 118954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 119054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 119154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 119254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 119354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Authorization", "password"); 119454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 119554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 119654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 119754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 119854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void contentLocationDoesNotPopulateCache() throws Exception { 119954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 120054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Location: /bar") 120154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 120254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 120354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 120454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 120554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/foo")))); 120654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/bar")))); 120754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 120854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 120954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotWriteToCache() throws Exception { 121054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 121154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 121254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 121354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 121454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 121554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 121654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 121754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 121854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 121954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 122054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 122154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotReadFromCache() throws Exception { 122254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 122354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 122454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 122554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 122654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 122754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 122854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 122954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 123054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 123154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 123254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 123354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultUseCachesSetsInitialValueOnly() throws Exception { 123454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = new URL("http://localhost/"); 123554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c1 = openConnection(url); 123654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c2 = openConnection(url); 123754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getDefaultUseCaches()); 123854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(false); 123954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 124054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getUseCaches()); 124154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c2.getUseCaches()); 124254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c3 = openConnection(url); 124354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(c3.getUseCaches()); 124454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 124554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(true); 124654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 124754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 124854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 124954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void connectionIsReturnedToPoolAfterConditionalSuccess() throws Exception { 125054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 125154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 125254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 125354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 125454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 125554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 125654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 125754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/a")))); 125854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/a")))); 125954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/b")))); 126054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 126154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, server.takeRequest().getSequenceNumber()); 126254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, server.takeRequest().getSequenceNumber()); 126354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.takeRequest().getSequenceNumber()); 126454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 126554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 126654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheMiss() throws Exception { 126754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 126854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 126954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 127054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 127154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 127254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 127354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 127454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 127554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 127654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 127754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 127854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 127954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(openConnection(server.getUrl("/")))); 128054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 128154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 128254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 128354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 128454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 128554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheHit() throws Exception { 128654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 128754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 128854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 128954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 129054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 129154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 129254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 129354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 129454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 129554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 129654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 129754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 129854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 129954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 130054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 130154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 130254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 130354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 130454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsFullCacheHit() throws Exception { 130554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A")); 130654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 130754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 130854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 130954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 131054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 131154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 131254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 131354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 131454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 131554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 131654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 131754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 131854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 131954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesChangedRequestHeaderField() throws Exception { 132054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 132154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 132254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 132354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 132454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 132554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 132654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 132754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection frConnection = openConnection(url); 132854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 132954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 133054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 133154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection enConnection = openConnection(url); 133254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-US"); 133354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 133454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 133554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 133654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesUnchangedRequestHeaderField() throws Exception { 133754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 133854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 133954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 134054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 134154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 134254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 134354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 134454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 134554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 134654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 134754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 134854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 134954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 135054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 135154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 135254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAbsentRequestHeaderField() throws Exception { 135354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 135454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 135554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 135654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 135754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 135854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 135954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 136054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 136154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 136254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 136354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAddedRequestHeaderField() throws Exception { 136454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 136554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 136654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 136754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 136854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 136954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 137054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 137154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection fooConnection = openConnection(server.getUrl("/")); 137254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 137354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(fooConnection)); 137454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 137554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 137654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesRemovedRequestHeaderField() throws Exception { 137754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 137854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 137954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 138054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 138154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 138254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 138354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection fooConnection = openConnection(server.getUrl("/")); 138454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 138554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(fooConnection)); 138654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 138754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 138854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 138954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyFieldsAreCaseInsensitive() throws Exception { 139054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 139154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: ACCEPT-LANGUAGE") 139254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 139354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 139454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 139554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 139654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 139754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 139854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 139954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 140054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 140154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("accept-language", "fr-CA"); 140254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 140354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 140454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 140554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithMatch() throws Exception { 140654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 140754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 140854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 140954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 141054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 141154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 141254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 141354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 141454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 141554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 141654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Charset", "UTF-8"); 141754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Encoding", "identity"); 141854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 141954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 142054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 142154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Charset", "UTF-8"); 142254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Encoding", "identity"); 142354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 142454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 142554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 142654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithNoMatch() throws Exception { 142754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 142854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 142954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 143054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 143154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 143254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 143354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 143454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 143554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection frConnection = openConnection(url); 143654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 143754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Charset", "UTF-8"); 143854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Encoding", "identity"); 143954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 144054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection enConnection = openConnection(url); 144154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-CA"); 144254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Charset", "UTF-8"); 144354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Encoding", "identity"); 144454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 144554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 144654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 144754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithMatch() throws Exception { 144854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 144954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 145054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 145154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 145254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 145354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 145454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 145554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 145654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 145754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 145854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 145954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 146054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 146154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 146254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 146354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 146454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 146554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 146654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithNoMatch() throws Exception { 146754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 146854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 146954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 147054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 147154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 147254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 147354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 147454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 147554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 147654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 147754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 147854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 147954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 148054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 148154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 148254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection2)); 148354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 148454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 148554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAsterisk() throws Exception { 148654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 148754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: *") 148854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 148954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 149054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 149154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 149254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 149354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 149454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 149554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 149654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAndHttps() throws Exception { 149754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 149854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 149954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 150054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 150154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 150254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 150354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 150454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 150554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(url); 150654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 150754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 150854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 150954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 151054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 151154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(url); 151254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setSSLSocketFactory(sslContext.getSocketFactory()); 151354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 151454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 151554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 151654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 151754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 151854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusCookies() throws Exception { 151954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 152054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";") 152154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 152254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 152354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 152454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 152554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";") 152654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 152754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 152854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 152954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 153054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 153154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=FIRST"); 153254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 153354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=SECOND"); 153454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 153554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 153654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsNetworkEndToEndHeaders() throws Exception { 153754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD") 153854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 153954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 154054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 154154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD, PUT") 154254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 154354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 154454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 154554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 154654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 154754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection1.getHeaderField("Allow")); 154854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 154954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 155054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 155154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD, PUT", connection2.getHeaderField("Allow")); 155254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 155354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 155454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsCachedHopByHopHeaders() throws Exception { 155554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: identity") 155654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 155754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 155854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 155954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: none") 156054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 156154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 156254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 156354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 156454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 156554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection1.getHeaderField("Transfer-Encoding")); 156654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 156754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 156854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 156954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection2.getHeaderField("Transfer-Encoding")); 157054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 157154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 157254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersDeletesCached100LevelWarnings() throws Exception { 157354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 199 test danger") 157454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 157554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 157654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 157754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 157854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 157954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 158054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 158154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 158254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("199 test danger", connection1.getHeaderField("Warning")); 158354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 158454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 158554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 158654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection2.getHeaderField("Warning")); 158754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 158854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 158954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersRetainsCached200LevelWarnings() throws Exception { 159054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 299 test danger") 159154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 159254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 159354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 159454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 159554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 159654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 159754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 159854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 159954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection1.getHeaderField("Warning")); 160054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 160154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 160254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 160354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection2.getHeaderField("Warning")); 160454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 160554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 160654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void assertCookies(URL url, String... expectedCookies) throws Exception { 160754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> actualCookies = new ArrayList<String>(); 160854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (HttpCookie cookie : cookieManager.getCookieStore().get(url.toURI())) { 160954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson actualCookies.add(cookie.toString()); 161054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 161154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList(expectedCookies), actualCookies); 161254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 161354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 161454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusRange() throws Exception { 161554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().setResponseCode(HttpURLConnection.HTTP_PARTIAL) 161654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 161754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Range: bytes 100-100/200") 161854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 161954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 162054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 162154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void conditionalHitUpdatesCache() throws Exception { 162254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS)) 162354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 162454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 162554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=30") 162654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Allow: GET, HEAD") 162754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 162854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 162954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 163054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 163154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // cache miss; seed the cache 163254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection1 = openConnection(server.getUrl("/a")); 163354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 163454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection1.getHeaderField("Allow")); 163554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 163654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // conditional cache hit; update the cache 163754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection2 = openConnection(server.getUrl("/a")); 163854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 163954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 164054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection2.getHeaderField("Allow")); 164154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 164254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // full cache hit 164354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection3 = openConnection(server.getUrl("/a")); 164454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection3)); 164554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection3.getHeaderField("Allow")); 164654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 164754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.getRequestCount()); 164854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 164954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1650faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderCached() throws IOException { 1651faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1652faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1653faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1654faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1655faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1656faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1657faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath URLConnection connection = openConnection(server.getUrl("/")); 1658faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath connection.addRequestProperty("Cache-Control", "only-if-cached"); 1659faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1660faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1661faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1662faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.CACHE.toString() + " 200", source); 1663faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1664faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1665faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheFetched() throws IOException { 1666faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1667faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1668faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(-31, TimeUnit.MINUTES))); 1669faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("B") 1670faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1671faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1672faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1673faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1674faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1675faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = openConnection(server.getUrl("/")); 1676faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("B", readAscii(connection)); 1677faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1678faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1679faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.CONDITIONAL_CACHE.toString() + " 200", source); 1680faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1681faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1682faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheNotFetched() throws IOException { 1683faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1684faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=0") 1685faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1686faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setResponseCode(304)); 1687faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1688faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1689faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1690faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = openConnection(server.getUrl("/")); 1691faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1692faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1693faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1694faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.CONDITIONAL_CACHE.toString() + " 304", source); 1695faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1696faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1697faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderFetched() throws IOException { 1698faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A")); 1699faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1700faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1701faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath URLConnection connection = openConnection(server.getUrl("/")); 1702faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1703faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1704faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1705faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.NETWORK.toString() + " 200", source); 1706faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1707faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1708faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void emptyResponseHeaderNameFromCacheIsLenient() throws Exception { 1709faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse() 1710faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=120") 1711faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader(": A") 1712faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .setBody("body")); 1713faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1714faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = client.open(server.getUrl("/")); 1715faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", connection.getHeaderField("")); 1716faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1717faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 171854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 171954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * @param delta the offset from the current date to use. Negative 172054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * values yield dates in the past; positive values yield dates in the 172154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * future. 172254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 172354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(long delta, TimeUnit timeUnit) { 172454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta))); 172554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 172654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 172754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(Date date) { 172854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 172954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson rfc1123.setTimeZone(TimeZone.getTimeZone("UTC")); 173054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return rfc1123.format(date); 173154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 173254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 173354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 173454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 173554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 173654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setDoOutput(true); 173754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream requestBody = invalidate.getOutputStream(); 173854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.write('x'); 173954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.close(); 174054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 174154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 174254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 174354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNotCached(MockResponse response) throws Exception { 174454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 174554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 174654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 174754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 174854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 174954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 175054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 175154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 175254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 175354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** @return the request with the conditional get headers. */ 175454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 175554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // scenario 1: condition succeeds 175654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A").setStatus("HTTP/1.1 200 A-OK")); 175754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 175854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 175954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // scenario 2: condition fails 176054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("B").setStatus("HTTP/1.1 200 B-OK")); 176154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 C-OK").setBody("C")); 176254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 176354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 176454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 176554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL valid = server.getUrl("/valid"); 176654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection1 = openConnection(valid); 176754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 176854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection1.getResponseCode()); 176954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection1.getResponseMessage()); 177054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection2 = openConnection(valid); 177154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 177254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 177354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection2.getResponseMessage()); 177454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 177554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL invalid = server.getUrl("/invalid"); 177654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection3 = openConnection(invalid); 177754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection3)); 177854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection3.getResponseCode()); 177954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B-OK", connection3.getResponseMessage()); 178054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection4 = openConnection(invalid); 178154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(connection4)); 178254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection4.getResponseCode()); 178354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C-OK", connection4.getResponseMessage()); 178454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 178554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // regular get 178654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); // conditional get 178754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 178854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 178954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertFullyCached(MockResponse response) throws Exception { 179054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 179154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("B")); 179254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 179354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 179454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 179554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 179654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 179754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 179854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 179954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 180054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Shortens the body of {@code response} but not the corresponding headers. 180154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Only useful to test how clients respond to the premature conclusion of 180254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * the HTTP body. 180354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 180454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 180554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setSocketPolicy(DISCONNECT_AT_END); 180654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = new ArrayList<String>(response.getHeaders()); 180754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 180854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.getHeaders().clear(); 180954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.getHeaders().addAll(headers); 181054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response; 181154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 181254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 181354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 181454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Reads {@code count} characters from the stream. If the stream is 181554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * exhausted before {@code count} characters can be read, the remaining 181654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * characters are returned and the stream is closed. 181754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 181854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection, int count) throws IOException { 181954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 182054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 182154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ? connection.getInputStream() : httpConnection.getErrorStream(); 182254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson StringBuilder result = new StringBuilder(); 182354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 0; i < count; i++) { 182454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int value = in.read(); 182554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (value == -1) { 18267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath in.close(); 182754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 182854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 182954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson result.append((char) value); 183054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 183154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return result.toString(); 183254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 183354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 183454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection) throws IOException { 183554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return readAscii(connection, Integer.MAX_VALUE); 183654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 183754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 183854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void reliableSkip(InputStream in, int length) throws IOException { 183954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson while (length > 0) { 184054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson length -= in.skip(length); 184154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 184254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 184354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 184454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertGatewayTimeout(HttpURLConnection connection) throws IOException { 184554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 184654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getInputStream(); 184754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 184854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (FileNotFoundException expected) { 184954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 185054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(504, connection.getResponseCode()); 185154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, connection.getErrorStream().read()); 185254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 185354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 185454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enum TransferKind { 185554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CHUNKED() { 185654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) 185754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 185854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setChunkedBody(content, chunkSize); 185954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 186054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 186154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson FIXED_LENGTH() { 186254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 186354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 186454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 186554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 186654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson END_OF_STREAM() { 186754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 186854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 18697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath response.setSocketPolicy(DISCONNECT_AT_END); 187054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 187154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (h.next().startsWith("Content-Length:")) { 187254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson h.remove(); 187354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 187454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 187654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 187754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 18787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 187954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson abstract void setBody(MockResponse response, byte[] content, int chunkSize) throws IOException; 188054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 188154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 188254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setBody(response, content.getBytes("UTF-8"), chunkSize); 188354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 188454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 188554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 188654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 188754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 188854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 188954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 189054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns a gzipped copy of {@code bytes}. */ 189154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public byte[] gzip(byte[] bytes) throws IOException { 189254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 189354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 189454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson gzippedOut.write(bytes); 189554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson gzippedOut.close(); 189654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return bytesOut.toByteArray(); 189754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 189854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 189954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private class InsecureResponseCache extends ResponseCache { 190054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 190154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return cache.put(uri, connection); 190254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 190354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 190454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheResponse get(URI uri, String requestMethod, 190554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Map<String, List<String>> requestHeaders) throws IOException { 190654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final CacheResponse response = cache.get(uri, requestMethod, requestHeaders); 190754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (response instanceof SecureCacheResponse) { 190854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new CacheResponse() { 190954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public InputStream getBody() throws IOException { 191054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response.getBody(); 191154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 191254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public Map<String, List<String>> getHeaders() throws IOException { 191354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response.getHeaders(); 191454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 19157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath }; 191654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 191754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response; 19187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 191954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 19207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath} 1921