HttpResponseCacheTest.java revision fddea0213028dd6d467f316584fac0f6e0745ce9
10c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson/* 20c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Copyright (C) 2011 The Android Open Source Project 30c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 40c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 50c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * you may not use this file except in compliance with the License. 60c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * You may obtain a copy of the License at 70c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 80c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 90c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Unless required by applicable law or agreed to in writing, software 110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * See the License for the specific language governing permissions and 140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * limitations under the License. 150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilsonpackage libcore.net.http; 180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1909336c914b4fc813e493acc82469b9ad89fd8694Jesse Wilsonimport com.google.mockwebserver.MockResponse; 2009336c914b4fc813e493acc82469b9ad89fd8694Jesse Wilsonimport com.google.mockwebserver.MockWebServer; 2109336c914b4fc813e493acc82469b9ad89fd8694Jesse Wilsonimport com.google.mockwebserver.RecordedRequest; 2209336c914b4fc813e493acc82469b9ad89fd8694Jesse Wilsonimport static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_END; 230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.BufferedReader; 240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.ByteArrayOutputStream; 25433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport java.io.File; 26c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilsonimport java.io.FileNotFoundException; 270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.IOException; 280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.InputStream; 290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.InputStreamReader; 300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.OutputStream; 31e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilsonimport java.lang.reflect.InvocationHandler; 320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheRequest; 330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheResponse; 34cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilsonimport java.net.CookieHandler; 35cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilsonimport java.net.CookieManager; 36cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilsonimport java.net.HttpCookie; 370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.HttpURLConnection; 380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.ResponseCache; 390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.SecureCacheResponse; 400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URI; 410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URISyntaxException; 420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URL; 430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URLConnection; 440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.security.Principal; 450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.security.cert.Certificate; 46953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.text.DateFormat; 47953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.text.SimpleDateFormat; 480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.ArrayList; 490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Arrays; 500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Collections; 510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Date; 52e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilsonimport java.util.Deque; 530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Iterator; 540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.List; 55953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.util.Locale; 560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Map; 57953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.util.TimeZone; 58433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport java.util.UUID; 590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.TimeUnit; 600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicInteger; 610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicReference; 620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.zip.GZIPOutputStream; 630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.HttpsURLConnection; 640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport junit.framework.TestCase; 650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport libcore.javax.net.ssl.TestSSLContext; 66e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilsonimport tests.io.MockOs; 670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 68396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilsonpublic final class HttpResponseCacheTest extends TestCase { 690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockWebServer server = new MockWebServer(); 70396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilson private HttpResponseCache cache; 71cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson private final MockOs mockOs = new MockOs(); 72cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson private final CookieManager cookieManager = new CookieManager(); 730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override protected void setUp() throws Exception { 750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson super.setUp(); 76433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson 77433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson String tmp = System.getProperty("java.io.tmpdir"); 78433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); 79396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilson cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE); 800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(cache); 81e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.install(); 82cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson CookieHandler.setDefault(cookieManager); 830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override protected void tearDown() throws Exception { 86e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.uninstall(); 870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.shutdown(); 88433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson ResponseCache.setDefault(null); 89fb4a6392a04b1f3a1124b3db6bae51d8cbfa53f8Jesse Wilson cache.getCache().delete(); 90cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson CookieHandler.setDefault(null); 910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson super.tearDown(); 920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Test that response caching is consistent with the RI and the spec. 960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 9884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testResponseCachingByResponseCode() throws Exception { 990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Test each documented HTTP/1.1 code, plus the first unused value in each range. 1000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 1010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We can't test 100 because it's not really a response. 1030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // assertCached(false, 100); 1040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 101); 1050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 102); 1060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 200); 1070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 201); 1080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 202); 1090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 203); 1100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 204); 1110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 205); 1124bc4b39a74774099b381ec9fd9ee0e2691ee7650Jesse Wilson assertCached(false, 206); // we don't cache partial responses 1130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 207); 11484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertCached(true, 300); 1150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 301); 1160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 302; i <= 308; ++i) { 1170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 400; i <= 406; ++i) { 1200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // (See test_responseCaching_407.) 1230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 408); 1240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 409); 1250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // (See test_responseCaching_410.) 1260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 411; i <= 418; ++i) { 1270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 500; i <= 506; ++i) { 1300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 1350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Response code 407 should only come from proxy servers. Android's client 1360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * throws if it is sent by an origin server. 1370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testOriginServerSends407() throws Exception { 1390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(407)); 1400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 1430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 1440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson conn.getResponseCode(); 1460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 1470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 1480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_responseCaching_410() throws Exception { 1520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // the HTTP spec permits caching 410s, but the RI doesn't. 15384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertCached(true, 410); 1540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertCached(boolean shouldPut, int responseCode) throws Exception { 1570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server = new MockWebServer(); 1585d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson MockResponse response = new MockResponse() 1590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 1610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(responseCode) 1620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABCDE") 1635d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .addHeader("WWW-Authenticate: challenge"); 1645d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) { 1655d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson response.addHeader("Proxy-Authenticate: Basic realm=\"protected area\""); 1665d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { 1675d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson response.addHeader("WWW-Authenticate: Basic realm=\"protected area\""); 1685d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson } 1695d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.enqueue(response); 1700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 1730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 1740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(responseCode, conn.getResponseCode()); 1750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // exhaust the content stream 17784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson readAscii(conn); 1780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 179433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson CacheResponse cached = cache.get(url.toURI(), "GET", 180433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson Collections.<String, List<String>>emptyMap()); 181433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson if (shouldPut) { 182433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson assertNotNull(Integer.toString(responseCode), cached); 183433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson cached.getBody().close(); 184433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } else { 185433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson assertNull(Integer.toString(responseCode), cached); 186433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } 1870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 1880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 1910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Test that we can interrogate the response when the cache is being 1920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * populated. http://code.google.com/p/android/issues/detail?id=7787 1930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCacheCallbackApis() throws Exception { 1950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final String body = "ABCDE"; 1960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final AtomicInteger cacheCount = new AtomicInteger(); 1970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 1990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setStatus("HTTP/1.1 200 Fantastic") 2000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("fgh: ijk") 2010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(body)); 2020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new ResponseCache() { 2050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 2060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 2070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 2080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 2100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection httpConnection = (HttpURLConnection) conn; 211953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson try { 212953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson httpConnection.getRequestProperties(); 213953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail(); 214953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (IllegalStateException expected) { 215953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 216953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson try { 217953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson httpConnection.addRequestProperty("K", "V"); 218953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail(); 219953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (IllegalStateException expected) { 220953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 2210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("HTTP/1.1 200 Fantastic", httpConnection.getHeaderField(null)); 2220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), 2230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson httpConnection.getHeaderFields().get(null)); 2240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, httpConnection.getResponseCode()); 2250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Fantastic", httpConnection.getResponseMessage()); 2260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(body.length(), httpConnection.getContentLength()); 2270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ijk", httpConnection.getHeaderField("fgh")); 2280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 2290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson httpConnection.getInputStream(); // the RI doesn't forbid this, but it should 2300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 2310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 2320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson cacheCount.incrementAndGet(); 2340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 2350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }); 2370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 239953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 2400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(body, readAscii(connection)); 2410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cacheCount.get()); 2420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithFixedLength() throws IOException { 2460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.FIXED_LENGTH); 2470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 2500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.CHUNKED); 2510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 2540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.END_OF_STREAM); 2550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 2580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 2590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://code.google.com/p/android/issues/detail?id=8175 2600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 2610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testResponseCaching(TransferKind transferKind) throws IOException { 2620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse() 2630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 2640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 2650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setStatus("HTTP/1.1 200 Fantastic"); 2660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 2670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Make sure that calling skip() doesn't omit bytes from the cache. 2710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 2720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = urlConnection.getInputStream(); 2730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("I love ", readAscii(urlConnection, "I love ".length())); 2740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson reliableSkip(in, "puppies but hate ".length()); 2750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("spiders", readAscii(urlConnection, "spiders".length())); 2760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(-1, in.read()); 2770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 278ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 279ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteAbortCount()); 2800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); // cached! 2820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in = urlConnection.getInputStream(); 2830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("I love puppies but hate spiders", 2840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(urlConnection, "I love puppies but hate spiders".length())); 2850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, urlConnection.getResponseCode()); 2860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 2870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(-1, in.read()); 289433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson in.close(); 290ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 291ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteAbortCount()); 292ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getRequestCount()); 293ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getHitCount()); 2940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSecureResponseCaching() throws IOException { 2970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 2980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 2990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 3030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 3060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 3100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String suite = connection.getCipherSuite(); 3110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<Certificate> localCerts = toListOrNull(connection.getLocalCertificates()); 3120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<Certificate> serverCerts = toListOrNull(connection.getServerCertificates()); 3130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Principal peerPrincipal = connection.getPeerPrincipal(); 3140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Principal localPrincipal = connection.getLocalPrincipal(); 3150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached! 3170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 320ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getRequestCount()); 321ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 322ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getHitCount()); 3230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(suite, connection.getCipherSuite()); 3250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(localCerts, toListOrNull(connection.getLocalCertificates())); 3260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(serverCerts, toListOrNull(connection.getServerCertificates())); 3270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(peerPrincipal, connection.getPeerPrincipal()); 3280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(localPrincipal, connection.getLocalPrincipal()); 3290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheReturnsInsecureResponseForSecureRequest() throws IOException { 3320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 3330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 3340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 3350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new InsecureResponseCache()); 3390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 3410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // not cached! 3450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("DEF", readAscii(connection)); 3470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 349a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson public void testResponseCachingAndRedirects() throws Exception { 3500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 3540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /foo")); 3550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 3590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 362953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 3630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 365953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection = server.getUrl("/").openConnection(); // cached! 3660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 368ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects 369ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getNetworkCount()); 370ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 3710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 373a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson public void testRedirectToCachedResult() throws Exception { 374a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse() 375a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .addHeader("Cache-Control: max-age=60") 376a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .setBody("ABC")); 377a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse() 378a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 379a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .addHeader("Location: /foo")); 380a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 381a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.play(); 382a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 383a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("ABC", readAscii(server.getUrl("/foo").openConnection())); 384a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request1 = server.takeRequest(); 385a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /foo HTTP/1.1", request1.getRequestLine()); 386a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(0, request1.getSequenceNumber()); 387a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 388a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("ABC", readAscii(server.getUrl("/bar").openConnection())); 389a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request2 = server.takeRequest(); 390a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /bar HTTP/1.1", request2.getRequestLine()); 391a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(1, request2.getSequenceNumber()); 392a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 393a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson // an unrelated request should reuse the pooled connection 394a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("DEF", readAscii(server.getUrl("/baz").openConnection())); 395a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request3 = server.takeRequest(); 396a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /baz HTTP/1.1", request3.getRequestLine()); 397a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(2, request3.getSequenceNumber()); 398a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } 399a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 4000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSecureResponseCachingAndRedirects() throws IOException { 4010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 4020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 4030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 4040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 4050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 4060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 4070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /foo")); 4080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 4090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 4100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 4110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 4120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 4130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 4160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 4180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached! 4200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 4220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 423ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 424ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 4250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCacheRequestHeaders() throws IOException, URISyntaxException { 4280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 4290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final AtomicReference<Map<String, List<String>>> requestHeadersRef 4320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson = new AtomicReference<Map<String, List<String>>>(); 4330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new ResponseCache() { 4340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 4350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 4360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestHeadersRef.set(requestHeaders); 4370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 4380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 4400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 4410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }); 4430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 4450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection urlConnection = url.openConnection(); 4460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("A", "android"); 4470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(urlConnection); 4480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("android"), requestHeadersRef.get().get("A")); 4490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 4530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 4540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 4570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.CHUNKED); 4580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 4610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 4620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Intentionally empty. This case doesn't make sense because there's no 4630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * such thing as a premature disconnect when the disconnect itself 4640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * indicates the end of the data stream. 4650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 4660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 4690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 4700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 4710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(truncateViolently(response, 16)); 4720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 4730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson BufferedReader reader = new BufferedReader(new InputStreamReader( 4760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.getUrl("/").openConnection().getInputStream())); 4770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", reader.readLine()); 4780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson reader.readLine(); 4800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("This implementation silently ignored a truncated HTTP body."); 4810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 482433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } finally { 483433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson reader.close(); 4840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 486ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 487ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteSuccessCount()); 4880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 4890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Request #2", readAscii(connection)); 490ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 491ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 4920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithContentLengthHeader() throws IOException { 4950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 4960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithChunkedEncoding() throws IOException { 4990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.CHUNKED); 5000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithNoLengthHeaders() throws IOException { 5030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 5040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 5070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 5080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 5090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 5100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 5110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 5120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 5140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = connection.getInputStream(); 5150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", readAscii(connection, 5)); 5160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 5170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 5180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.read(); 5190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Expected an IOException because the stream is closed."); 5200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 5210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 523ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 524ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteSuccessCount()); 5250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = server.getUrl("/").openConnection(); 52684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("Request #2", readAscii(connection)); 527ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 528ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 5290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 531953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 53221dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 105 seconds ago 53321dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 5 seconds ago 53421dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (105 - 5) / 10 = 10 seconds 53521dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds from now 536953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 53721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 538953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 539953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 540953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 541953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 542953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URL url = server.getUrl("/"); 543953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 544953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 545953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 546953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertNull(connection.getHeaderField("Warning")); 54721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 54821dddca4064527116af7a1553de502c6d11138daJesse Wilson 54921dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testDefaultExpirationDateConditionallyCached() throws Exception { 55021dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 115 seconds ago 55121dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 15 seconds ago 55221dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (115 - 15) / 10 = 10 seconds 55321dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds ago 55421dddca4064527116af7a1553de502c6d11138daJesse Wilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 5550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 55621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 55721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 5580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 562953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 563953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // last modified: 105 days ago 564953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // served: 5 days ago 565953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // default lifetime: (105 - 5) / 10 = 10 days 566953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // expires: 10 days from served date = 5 days from now 567953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 568953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 569953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 570953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 571953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 572953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 573953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 574953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 575953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 576953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 577953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 578953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 579953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 58021dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testNoDefaultExpirationForUrlsWithQueryString() throws Exception { 58121dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 58221dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 58321dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 58421dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 58521dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 58621dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 58721dddca4064527116af7a1553de502c6d11138daJesse Wilson 58821dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/?foo=bar"); 58921dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(url.openConnection())); 59021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 59121dddca4064527116af7a1553de502c6d11138daJesse Wilson } 59221dddca4064527116af7a1553de502c6d11138daJesse Wilson 5930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithLastModifiedHeader() throws Exception { 5940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 5950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 5960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 5970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 5980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 6000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithNoLastModifiedHeader() throws Exception { 6030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 6040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 6050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInTheFuture() throws Exception { 6080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 6100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgePreferredWithMaxAgeAndExpires() throws Exception { 6130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 6150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 6160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 6200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 6210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 6220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 6230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 6240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 6260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 6270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 63084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson /* 63184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * Chrome interprets max-age relative to the local clock. Both our cache 63284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * and Firefox both use the earlier of the local and server's clock. 63384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson */ 6340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 6350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 6360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithDateHeader() throws Exception { 6400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 6420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithNoDateHeader() throws Exception { 6460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 650adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeWithLastModifiedButNoServedDate() throws Exception { 651adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 652adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 653adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 654adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 655adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 656adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 657adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 658adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 659adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 660adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 661adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 662adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 66321dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverLowerSharedMaxAge() throws Exception { 66421dddca4064527116af7a1553de502c6d11138daJesse Wilson assertFullyCached(new MockResponse() 66521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 66621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60") 66721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=180")); 66821dddca4064527116af7a1553de502c6d11138daJesse Wilson } 66921dddca4064527116af7a1553de502c6d11138daJesse Wilson 67021dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverHigherMaxAge() throws Exception { 67121dddca4064527116af7a1553de502c6d11138daJesse Wilson assertNotCached(new MockResponse() 67221dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 67321dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=180") 67421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60")); 67521dddca4064527116af7a1553de502c6d11138daJesse Wilson } 67621dddca4064527116af7a1553de502c6d11138daJesse Wilson 6770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodOptionsIsNotCached() throws Exception { 6780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("OPTIONS", false); 6790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodGetIsCached() throws Exception { 6820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("GET", true); 6830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodHeadIsNotCached() throws Exception { 6860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("HEAD", false); 6880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPostIsNotCached() throws Exception { 6910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("POST", false); 6930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPutIsNotCached() throws Exception { 6960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("PUT", false); 6970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodDeleteIsNotCached() throws Exception { 7000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("DELETE", false); 7010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodTraceIsNotCached() throws Exception { 7040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("TRACE", false); 7050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 7080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 7090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache (potentially) 7100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. expect a cache hit or miss 7110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 7130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 1")); 7150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 7160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 2")); 7170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection request1 = (HttpURLConnection) url.openConnection(); 7220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson request1.setRequestMethod(requestMethod); 7230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, request1); 7240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 7250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 726953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection request2 = url.openConnection(); 7270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (expectCached) { 7280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 7290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } else { 7300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 7310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPostInvalidatesCache() throws Exception { 7350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("POST"); 7360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPutInvalidatesCache() throws Exception { 7390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("PUT"); 7400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testDeleteMethodInvalidatesCache() throws Exception { 7430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("DELETE"); 7440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testMethodInvalidates(String requestMethod) throws Exception { 7470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 7480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache 7490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. invalidate it 7500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 3. expect a cache miss 7510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 7530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 7540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 7550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("C")); 7560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 7610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection invalidate = (HttpURLConnection) url.openConnection(); 7630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setRequestMethod(requestMethod); 7640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, invalidate); 7650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(invalidate)); 7660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("C", readAscii(url.openConnection())); 7680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtag() throws Exception { 7710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1")); 7730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1")); 7740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInThePast() throws Exception { 7770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 7820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 7840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInTheFuture() throws Exception { 7880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 7890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 7910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 7920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCache() throws Exception { 7950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 7960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 7990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 8000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 8010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 8020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-cache")); 8040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 8050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 8060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCache() throws Exception { 8090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 8100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 8130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 8140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 8150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 8160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Pragma: no-cache")); 8180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 8190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 8200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStore() throws Exception { 8230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 8240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 8270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 8280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-store")); 8310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPartialRangeResponsesDoNotCorruptCache() throws Exception { 8340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 8350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. request a range 8360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. request a full document, expecting a cache miss 8370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 8380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("AA") 8390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 8400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Range: bytes 1000-1001/2000")); 8420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("BB")); 8430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 8460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection range = url.openConnection(); 8480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson range.addRequestProperty("Range", "bytes=1000-1001"); 8490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("AA", readAscii(range)); 8500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("BB", readAscii(url.openConnection())); 8520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerReturnsDocumentOlderThanCache() throws Exception { 8550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 8560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B") 8590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 8600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 8630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndConditionalCache() throws Exception { 8690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndFullCache() throws Exception { 8750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 8780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 8810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response 8820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(gzip("ABCABCABC".getBytes("UTF-8"))) 8830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Encoding: gzip")); 8840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 8850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpiresDateBeforeModifiedDate() throws Exception { 8920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertConditionallyCached(new MockResponse() 8930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 8940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 8950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 897adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMaxAge() throws IOException { 898adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 899adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 900adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 901adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 902adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 903adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 904adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 905adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 906adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 907adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 908adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "max-age=30"); 909adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 910adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 911adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 912adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMinFresh() throws IOException { 913adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 914adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60") 915adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 916adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 917adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 918adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 919adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 920adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 921adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 922adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 923adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 924adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 925adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 926c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestMaxStale() throws IOException { 927c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 928c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=120") 929c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 930c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("B")); 931c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 932c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 933c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 934c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 935c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 936c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 937c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(connection)); 938953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("110 HttpURLConnection \"Response is stale\"", 939953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 940c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 941c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 9422f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson public void testRequestMaxStaleNotHonoredWithMustRevalidate() throws IOException { 9432f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setBody("A") 9442f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Cache-Control: max-age=120, must-revalidate") 9452f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 9462f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 9472f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 9482f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.play(); 9492f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 9502f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 9512f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 9522f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 9532f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("B", readAscii(connection)); 9542f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 9552f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 956c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithNoResponseCached() throws IOException { 957c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson // (no responses enqueued) 958c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 959c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 960953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 961c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 962fddea0213028dd6d467f316584fac0f6e0745ce9Elliott Hughes assertGatewayTimeout(connection); 963c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 964c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 965c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithFullResponseCached() throws IOException { 966c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 967c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 968c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 969c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 970c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 971c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 972c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 973c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 974c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 975c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 976c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 977c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithConditionalResponseCached() throws IOException { 978c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 979c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 980c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 981c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 982c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 983c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 984953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 985c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 986fddea0213028dd6d467f316584fac0f6e0745ce9Elliott Hughes assertGatewayTimeout(connection); 987c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 988c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 989c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 990c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A")); 991c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 992c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 993c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 994953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 995c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 996fddea0213028dd6d467f316584fac0f6e0745ce9Elliott Hughes assertGatewayTimeout(connection); 997c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 998c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 99984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestCacheControlNoCache() throws Exception { 100084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 100184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 100284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 100384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 100484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 100584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 100684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 100784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 100884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 100984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 101084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 101184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Cache-Control", "no-cache"); 101284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 101384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 101484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 101584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestPragmaNoCache() throws Exception { 101684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 101784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 101884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 101984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 102084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 102184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 102284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 102384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 102484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 102584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 102684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 102784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Pragma", "no-cache"); 102884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 102984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 103084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 103184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 103284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 103384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("ETag: v3") 103484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 103584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 103684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 103784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-Modified-Since", ifModifiedSinceDate); 103884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 103984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate)); 104084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-None-Match: v3")); 104184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 104284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 104384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 104484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 104584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 104684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 104784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 104884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 104984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 105084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-None-Match", "v1"); 105184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 105284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 105384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate)); 105484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 105584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 105684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 105784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String conditionValue) throws Exception { 105884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(seed.setBody("A")); 105984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 106084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 106184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 106284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 106384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 106484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 106584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 106684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty(conditionName, conditionValue); 106784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 106884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 106984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 107084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.takeRequest(); // seed 107184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson return server.takeRequest(); 107284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 107384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 10749531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson public void testSetIfModifiedSince() throws Exception { 10759531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson Date since = new Date(); 10769531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson server.enqueue(new MockResponse().setBody("A")); 10779531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson server.play(); 10789531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 10799531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson URL url = server.getUrl("/"); 10809531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson URLConnection connection = url.openConnection(); 10819531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson connection.setIfModifiedSince(since.getTime()); 10829531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson assertEquals("A", readAscii(connection)); 10839531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson RecordedRequest request = server.takeRequest(); 10849531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson assertTrue(request.getHeaders().contains("If-Modified-Since: " + formatDate(since))); 10859531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 10869531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 108784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedConditionWithoutCachedResult() throws Exception { 108884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 108984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 109084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 109184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 109284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 109384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 109484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 109584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 109684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 109784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 1098c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 109921dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationRequestHeaderPreventsCaching() throws Exception { 110021dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 110121dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES)) 110221dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60") 110321dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 110421dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 110521dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 110621dddca4064527116af7a1553de502c6d11138daJesse Wilson 110721dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/"); 1108953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 110921dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.addRequestProperty("Authorization", "password"); 111021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(connection)); 111121dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 111221dddca4064527116af7a1553de502c6d11138daJesse Wilson } 111321dddca4064527116af7a1553de502c6d11138daJesse Wilson 111421dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithSMaxAge() throws Exception { 111521dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 111621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60")); 111721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 111821dddca4064527116af7a1553de502c6d11138daJesse Wilson 111921dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithPublic() throws Exception { 112021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 112121dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: public")); 112221dddca4064527116af7a1553de502c6d11138daJesse Wilson } 112321dddca4064527116af7a1553de502c6d11138daJesse Wilson 112421dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithMustRevalidate() throws Exception { 112521dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 112621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: must-revalidate")); 112721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 112821dddca4064527116af7a1553de502c6d11138daJesse Wilson 112921dddca4064527116af7a1553de502c6d11138daJesse Wilson public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception { 113021dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(response 113121dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60") 113221dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 113321dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 113421dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 113521dddca4064527116af7a1553de502c6d11138daJesse Wilson 113621dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/"); 1137953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 113821dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.addRequestProperty("Authorization", "password"); 113921dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(connection)); 114021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(url.openConnection())); 114121dddca4064527116af7a1553de502c6d11138daJesse Wilson } 114221dddca4064527116af7a1553de502c6d11138daJesse Wilson 1143953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testContentLocationDoesNotPopulateCache() throws Exception { 1144953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 1145953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Cache-Control: max-age=60") 1146953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Content-Location: /bar") 1147953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 1148953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1149953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 1150953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1151953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/foo").openConnection())); 1152953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("B", readAscii(server.getUrl("/bar").openConnection())); 1153953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1154953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 115519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testUseCachesFalseDoesNotWriteToCache() throws Exception { 115619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse() 115719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .addHeader("Cache-Control: max-age=60") 115819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .setBody("A").setBody("A")); 115919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 116019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.play(); 116119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 116219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 116319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson connection.setUseCaches(false); 116419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("A", readAscii(connection)); 116519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 116619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 116719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 116819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testUseCachesFalseDoesNotReadFromCache() throws Exception { 116919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse() 117019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .addHeader("Cache-Control: max-age=60") 117119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .setBody("A").setBody("A")); 117219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 117319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.play(); 117419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 117519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 117619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 117719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson connection.setUseCaches(false); 117819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("B", readAscii(connection)); 117919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 118019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 118119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testDefaultUseCachesSetsInitialValueOnly() throws Exception { 118219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URL url = new URL("http://localhost/"); 118319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection c1 = url.openConnection(); 118419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection c2 = url.openConnection(); 118519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertTrue(c1.getDefaultUseCaches()); 118619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson c1.setDefaultUseCaches(false); 118719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson try { 118819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertTrue(c1.getUseCaches()); 118919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertTrue(c2.getUseCaches()); 119019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection c3 = url.openConnection(); 119119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertFalse(c3.getUseCaches()); 119219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } finally { 119319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson c1.setDefaultUseCaches(true); 119419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 119519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 119619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 11972f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson public void testConnectionIsReturnedToPoolAfterConditionalSuccess() throws Exception { 11982f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse() 11992f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 12002f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Cache-Control: max-age=0") 12012f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .setBody("A")); 12022f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 12032f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 12042f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.play(); 12052f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 12062f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/a").openConnection())); 12072f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/a").openConnection())); 12082f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("B", readAscii(server.getUrl("/b").openConnection())); 12092f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 12102f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 12112f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 12122f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals(2, server.takeRequest().getSequenceNumber()); 12132f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 12142f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 1215757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testStatisticsConditionalCacheMiss() throws Exception { 1216757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1217757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1218757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Cache-Control: max-age=0") 1219757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setBody("A")); 1220757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setBody("B")); 1221757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setBody("C")); 1222757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.play(); 1223757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1224757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1225ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getRequestCount()); 1226ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1227ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1228757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 1229757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("C", readAscii(server.getUrl("/").openConnection())); 1230ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getRequestCount()); 1231ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getNetworkCount()); 1232ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1233757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1234757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1235757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testStatisticsConditionalCacheHit() throws Exception { 1236757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1237757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1238757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Cache-Control: max-age=0") 1239757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setBody("A")); 1240757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1241757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1242757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.play(); 1243757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1244757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1245ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getRequestCount()); 1246ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1247ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1248757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1249757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1250ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getRequestCount()); 1251ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getNetworkCount()); 1252ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 1253757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1254757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1255757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testStatisticsFullCacheHit() throws Exception { 1256757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1257757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Cache-Control: max-age=60") 1258757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setBody("A")); 1259757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.play(); 1260757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1261757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1262ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getRequestCount()); 1263ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1264ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1265757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1266757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1267ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getRequestCount()); 1268ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1269ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 1270757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1271757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 12726f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesChangedRequestHeaderField() throws Exception { 12736f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 12746f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 12756f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 12766f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 12776f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 12786f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 12796f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12806f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 12816f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpURLConnection frConnection = (HttpURLConnection) url.openConnection(); 12826f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 12836f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(frConnection)); 12846f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12856f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpURLConnection enConnection = (HttpURLConnection) url.openConnection(); 12866f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Language", "en-US"); 12876f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(enConnection)); 12886f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 12896f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12906f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesUnchangedRequestHeaderField() throws Exception { 12916f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 12926f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 12936f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 12946f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 12956f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 12966f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 12976f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12986f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 12996f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 13006f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 13016f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 13026f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 13036f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 13046f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 13056f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13066f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13076f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesAbsentRequestHeaderField() throws Exception { 13086f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13096f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13106f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Foo") 13116f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13126f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13136f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13146f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13156f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 13166f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 13176f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13186f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13196f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesAddedRequestHeaderField() throws Exception { 13206f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13216f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13226f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Foo") 13236f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13246f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13256f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13266f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13276f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 13286f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection fooConnection = server.getUrl("/").openConnection(); 13296f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson fooConnection.addRequestProperty("Foo", "bar"); 13306f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(fooConnection)); 13316f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13326f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13336f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesRemovedRequestHeaderField() throws Exception { 13346f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13356f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13366f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Foo") 13376f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13386f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13396f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13406f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13416f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection fooConnection = server.getUrl("/").openConnection(); 13426f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson fooConnection.addRequestProperty("Foo", "bar"); 13436f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(fooConnection)); 13446f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 13456f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13466f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13476f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryFieldsAreCaseInsensitive() throws Exception { 13486f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13496f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13506f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: ACCEPT-LANGUAGE") 13516f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13526f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13536f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13546f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13556f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 13566f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 13576f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 13586f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 13596f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 13606f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("accept-language", "fr-CA"); 13616f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 13626f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13636f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13646f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldsWithMatch() throws Exception { 13656f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13666f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13676f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language, Accept-Charset") 13686f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Encoding") 13696f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13706f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13716f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13726f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13736f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 13746f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 13756f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 13766f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Charset", "UTF-8"); 13776f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Encoding", "identity"); 13786f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 13796f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 13806f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 13816f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Charset", "UTF-8"); 13826f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Encoding", "identity"); 13836f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 13846f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13856f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13866f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldsWithNoMatch() throws Exception { 13876f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13886f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13896f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language, Accept-Charset") 13906f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Encoding") 13916f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13926f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13936f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13946f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13956f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 13966f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection frConnection = url.openConnection(); 13976f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 13986f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Charset", "UTF-8"); 13996f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Encoding", "identity"); 14006f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(frConnection)); 14016f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection enConnection = url.openConnection(); 14026f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Language", "en-CA"); 14036f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Charset", "UTF-8"); 14046f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Encoding", "identity"); 14056f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(enConnection)); 14066f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14076f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14086f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldValuesWithMatch() throws Exception { 14096f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14106f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14116f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 14126f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14136f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14146f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14156f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14166f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 14176f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 14186f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 14196f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "en-US"); 14206f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 14216f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14226f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 14236f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 14246f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "en-US"); 14256f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 14266f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14276f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14286f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldValuesWithNoMatch() throws Exception { 14296f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14306f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14316f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 14326f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14336f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14346f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14356f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14366f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 14376f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 14386f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 14396f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "en-US"); 14406f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 14416f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14426f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 14436f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 14446f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "en-US"); 14456f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(connection2)); 14466f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14476f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14486f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryAsterisk() throws Exception { 14496f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14506f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14516f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: *") 14526f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14536f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14546f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14556f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14566f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 14576f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 14586f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14596f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14606f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryAndHttps() throws Exception { 14616f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 14626f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 14636f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14646f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14656f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 14666f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14676f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14686f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14696f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14706f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 14716f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpsURLConnection connection1 = (HttpsURLConnection) url.openConnection(); 14726f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 14736f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "en-US"); 14746f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 14756f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14766f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpsURLConnection connection2 = (HttpsURLConnection) url.openConnection(); 14776f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 14786f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "en-US"); 14796f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 14806f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14816f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 1482e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson public void testDiskWriteFailureCacheDegradation() throws Exception { 1483e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson Deque<InvocationHandler> writeHandlers = mockOs.getHandlers("write"); 1484e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson int i = 0; 1485e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson boolean hasMoreScenarios = true; 1486e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson while (hasMoreScenarios) { 1487e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueNormal("write", i++); 1488e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueFault("write"); 1489e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson exercisePossiblyFaultyCache(false); 1490e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson hasMoreScenarios = writeHandlers.isEmpty(); 1491e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson writeHandlers.clear(); 1492e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1493e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson System.out.println("Exercising the cache performs " + (i - 1) + " writes."); 1494e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1495e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 1496e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson public void testDiskReadFailureCacheDegradation() throws Exception { 1497e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson Deque<InvocationHandler> readHandlers = mockOs.getHandlers("read"); 1498e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson int i = 0; 1499e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson boolean hasMoreScenarios = true; 1500e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson while (hasMoreScenarios) { 1501e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueNormal("read", i++); 1502e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueFault("read"); 1503e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson exercisePossiblyFaultyCache(true); 1504e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson hasMoreScenarios = readHandlers.isEmpty(); 1505e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson readHandlers.clear(); 1506e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1507e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson System.out.println("Exercising the cache performs " + (i - 1) + " reads."); 1508e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1509e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 1510cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson public void testCachePlusCookies() throws Exception { 1511cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 15125d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .addHeader("Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";") 1513cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1514cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Cache-Control: max-age=0") 1515cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setBody("A")); 1516cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 15175d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .addHeader("Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";") 1518cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1519cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.play(); 1520cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1521cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URL url = server.getUrl("/"); 1522cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 1523cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertCookies(url, "a=FIRST"); 1524cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 1525cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertCookies(url, "a=SECOND"); 1526cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1527cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1528cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson public void testGetHeadersReturnsNetworkEndToEndHeaders() throws Exception { 1529cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1530cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Allow: GET, HEAD") 1531cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1532cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Cache-Control: max-age=0") 1533cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setBody("A")); 1534cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1535cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Allow: GET, HEAD, PUT") 1536cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1537cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.play(); 1538cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1539cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection1 = server.getUrl("/").openConnection(); 1540cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection1)); 1541cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("GET, HEAD", connection1.getHeaderField("Allow")); 1542cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1543cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection2 = server.getUrl("/").openConnection(); 1544cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection2)); 1545cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("GET, HEAD, PUT", connection2.getHeaderField("Allow")); 1546cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1547cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1548cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson public void testGetHeadersReturnsCachedHopByHopHeaders() throws Exception { 1549cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1550cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Transfer-Encoding: identity") 1551cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1552cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Cache-Control: max-age=0") 1553cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setBody("A")); 1554cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1555cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Transfer-Encoding: none") 1556cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1557cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.play(); 1558cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1559cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection1 = server.getUrl("/").openConnection(); 1560cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection1)); 1561cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("identity", connection1.getHeaderField("Transfer-Encoding")); 1562cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1563cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection2 = server.getUrl("/").openConnection(); 1564cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection2)); 1565cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("identity", connection2.getHeaderField("Transfer-Encoding")); 1566cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1567cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1568cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson public void testGetHeadersDeletesCached100LevelWarnings() throws Exception { 1569cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1570cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Warning: 199 test danger") 1571cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1572cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Cache-Control: max-age=0") 1573cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setBody("A")); 1574cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1575cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1576cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.play(); 1577cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1578cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection1 = server.getUrl("/").openConnection(); 1579cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection1)); 1580cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("199 test danger", connection1.getHeaderField("Warning")); 1581cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1582cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection2 = server.getUrl("/").openConnection(); 1583cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection2)); 1584cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals(null, connection2.getHeaderField("Warning")); 1585cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1586cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1587cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson public void testGetHeadersRetainsCached200LevelWarnings() throws Exception { 1588cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1589cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Warning: 299 test danger") 1590cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1591cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Cache-Control: max-age=0") 1592cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setBody("A")); 1593cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.enqueue(new MockResponse() 1594cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1595cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson server.play(); 1596cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1597cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection1 = server.getUrl("/").openConnection(); 1598cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection1)); 1599cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("299 test danger", connection1.getHeaderField("Warning")); 1600cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1601cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson URLConnection connection2 = server.getUrl("/").openConnection(); 1602cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("A", readAscii(connection2)); 1603cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals("299 test danger", connection2.getHeaderField("Warning")); 1604cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1605cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1606cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson public void assertCookies(URL url, String... expectedCookies) throws Exception { 1607cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson List<String> actualCookies = new ArrayList<String>(); 1608cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson for (HttpCookie cookie : cookieManager.getCookieStore().get(url.toURI())) { 1609cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson actualCookies.add(cookie.toString()); 1610cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1611cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertEquals(Arrays.asList(expectedCookies), actualCookies); 1612cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1613cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 1614cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson public void testCachePlusRange() throws Exception { 1615cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson assertNotCached(new MockResponse() 1616cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 1617cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 1618cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Content-Range: bytes 100-100/200") 1619cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson .addHeader("Cache-Control: max-age=60")); 1620cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson } 1621cd8c1dd724036dcd1b7c27542cc4d745391b8d04Jesse Wilson 16225d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson public void testConditionalHitUpdatesCache() throws Exception { 16235d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.enqueue(new MockResponse() 16245d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS)) 16255d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .addHeader("Cache-Control: max-age=0") 16265d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .setBody("A")); 16275d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.enqueue(new MockResponse() 16285d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .addHeader("Cache-Control: max-age=30") 16295d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .addHeader("Allow: GET, HEAD") 16305d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 16315d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.enqueue(new MockResponse().setBody("B")); 16325d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.play(); 16335d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson 16345d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson // cache miss; seed the cache 16355d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson HttpURLConnection connection1 = (HttpURLConnection) server.getUrl("/a").openConnection(); 16365d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("A", readAscii(connection1)); 16375d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals(null, connection1.getHeaderField("Allow")); 16385d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson 16395d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson // conditional cache hit; update the cache 16405d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson HttpURLConnection connection2 = (HttpURLConnection) server.getUrl("/a").openConnection(); 16415d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 16425d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("A", readAscii(connection2)); 16435d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("GET, HEAD", connection2.getHeaderField("Allow")); 16445d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson 16455d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson // full cache hit 16465d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson HttpURLConnection connection3 = (HttpURLConnection) server.getUrl("/a").openConnection(); 16475d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("A", readAscii(connection3)); 16485d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("GET, HEAD", connection3.getHeaderField("Allow")); 16495d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson 16505d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals(2, server.getRequestCount()); 16515d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson } 16525d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson 16530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 16540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @param delta the offset from the current date to use. Negative 16550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * values yield dates in the past; positive values yield dates in the 16560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * future. 16570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1658953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private String formatDate(long delta, TimeUnit timeUnit) { 16599531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta))); 16609531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 16619531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 16629531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson private String formatDate(Date date) { 1663953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 1664953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson rfc1123.setTimeZone(TimeZone.getTimeZone("UTC")); 1665953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson return rfc1123.format(date); 16660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 16690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 16700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 16710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setDoOutput(true); 16720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream requestBody = invalidate.getOutputStream(); 16730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.write('x'); 16740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.close(); 16750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNotCached(MockResponse response) throws Exception { 16790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 16800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 16810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 16820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 16840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 16850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(url.openConnection())); 16860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1688e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson private void exercisePossiblyFaultyCache(boolean permitReadBodyFailures) throws Exception { 1689e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.shutdown(); 1690e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server = new MockWebServer(); 1691e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.enqueue(new MockResponse() 1692e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson .addHeader("Cache-Control: max-age=60") 1693e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson .setBody("A")); 1694e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1695e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.play(); 1696e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 1697e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson URL url = server.getUrl("/" + UUID.randomUUID()); 1698e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 1699e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 1700e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson URLConnection connection = url.openConnection(); 1701e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson InputStream in = connection.getInputStream(); 1702e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson try { 1703e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson int bodyChar = in.read(); 1704e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson assertTrue(bodyChar == 'A' || bodyChar == 'B'); 1705e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson assertEquals(-1, in.read()); 1706e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } catch (IOException e) { 1707e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson if (!permitReadBodyFailures) { 1708e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson throw e; 1709e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1710e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1711e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1712e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 17130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 17140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @return the request with the conditional get headers. 17150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 17160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 17170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 1: condition succeeds 17185d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.enqueue(response.setBody("A").setStatus("HTTP/1.1 200 A-OK")); 17190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 17200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 2: condition fails 17225d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.enqueue(response.setBody("B").setStatus("HTTP/1.1 200 B-OK")); 17235d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 C-OK").setBody("C")); 17240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 17260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL valid = server.getUrl("/valid"); 17285d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson HttpURLConnection connection1 = (HttpURLConnection) valid.openConnection(); 17295d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("A", readAscii(connection1)); 17305d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals(HttpURLConnection.HTTP_OK, connection1.getResponseCode()); 17315d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("A-OK", connection1.getResponseMessage()); 17325d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson HttpURLConnection connection2 = (HttpURLConnection) valid.openConnection(); 17335d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("A", readAscii(connection2)); 17345d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 17355d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("A-OK", connection2.getResponseMessage()); 17360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL invalid = server.getUrl("/invalid"); 17385d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson HttpURLConnection connection3 = (HttpURLConnection) invalid.openConnection(); 17395d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("B", readAscii(connection3)); 17405d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals(HttpURLConnection.HTTP_OK, connection3.getResponseCode()); 17415d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("B-OK", connection3.getResponseMessage()); 17425d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson HttpURLConnection connection4 = (HttpURLConnection) invalid.openConnection(); 17435d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("C", readAscii(connection4)); 17445d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals(HttpURLConnection.HTTP_OK, connection4.getResponseCode()); 17455d7e0fc1af3141aa41e9c21d74da3c36b933517fJesse Wilson assertEquals("C-OK", connection4.getResponseMessage()); 17460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.takeRequest(); // regular get 17480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return server.takeRequest(); // conditional get 17490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertFullyCached(MockResponse response) throws Exception { 17520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 17530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("B")); 17540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 17550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 17570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 17580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 17590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 17620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Shortens the body of {@code response} but not the corresponding headers. 17630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Only useful to test how clients respond to the premature conclusion of 17640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * the HTTP body. 17650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 17660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 17670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 17680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = new ArrayList<String>(response.getHeaders()); 17690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 17700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().clear(); 17710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().addAll(headers); 17720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 17730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 17760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Reads {@code count} characters from the stream. If the stream is 17770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * exhausted before {@code count} characters can be read, the remaining 17780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * characters are returned and the stream is closed. 17790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 17800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection, int count) throws IOException { 178184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 178284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 178384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson ? connection.getInputStream() 178484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson : httpConnection.getErrorStream(); 17850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson StringBuilder result = new StringBuilder(); 17860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 0; i < count; i++) { 17870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson int value = in.read(); 17880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (value == -1) { 17890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 17900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 17910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson result.append((char) value); 17930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return result.toString(); 17950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection) throws IOException { 17980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return readAscii(connection, Integer.MAX_VALUE); 17990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 18010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void reliableSkip(InputStream in, int length) throws IOException { 18020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson while (length > 0) { 18030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson length -= in.skip(length); 18040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1807fddea0213028dd6d467f316584fac0f6e0745ce9Elliott Hughes private void assertGatewayTimeout(HttpURLConnection connection) throws IOException { 1808c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson try { 1809c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.getInputStream(); 1810c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson fail(); 1811c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } catch (FileNotFoundException expected) { 1812c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1813fddea0213028dd6d467f316584fac0f6e0745ce9Elliott Hughes assertEquals(504, connection.getResponseCode()); 1814953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(-1, connection.getErrorStream().read()); 1815c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1816c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 18170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson enum TransferKind { 18180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson CHUNKED() { 18190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) 18200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 18210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setChunkedBody(content, chunkSize); 18220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 18240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson FIXED_LENGTH() { 18250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 18260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 18270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 18290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson END_OF_STREAM() { 18300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 18310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 18320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 18330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 18340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (h.next().startsWith("Content-Length:")) { 18350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson h.remove(); 18360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 18370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 18410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 18420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson abstract void setBody(MockResponse response, byte[] content, int chunkSize) 18430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException; 18440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 18450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 18460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson setBody(response, content.getBytes("UTF-8"), chunkSize); 18470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 18500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 18510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 18520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 18540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 18550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Returns a gzipped copy of {@code bytes}. 18560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 18570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public byte[] gzip(byte[] bytes) throws IOException { 18580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 18590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 18600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.write(bytes); 18610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.close(); 18620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return bytesOut.toByteArray(); 18630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1865433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson private class InsecureResponseCache extends ResponseCache { 18660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 1867433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson return cache.put(uri, connection); 18680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 18700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 18710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 1872433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson final CacheResponse response = cache.get(uri, requestMethod, requestHeaders); 18730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (response instanceof SecureCacheResponse) { 18740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return new CacheResponse() { 18750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public InputStream getBody() throws IOException { 18760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getBody(); 18770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public Map<String, List<String>> getHeaders() throws IOException { 18790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getHeaders(); 18800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 18820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 18840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 18860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson} 1887