HttpResponseCacheTest.java revision e5eb80e6adaab18ff7372adcd09f9e1af3a76871
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 190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.BufferedReader; 200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.ByteArrayOutputStream; 21433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport java.io.File; 22c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilsonimport java.io.FileNotFoundException; 230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.IOException; 240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.InputStream; 250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.InputStreamReader; 260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.OutputStream; 27e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilsonimport java.lang.reflect.InvocationHandler; 280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheRequest; 290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheResponse; 300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.HttpURLConnection; 310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.ResponseCache; 320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.SecureCacheResponse; 330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URI; 340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URISyntaxException; 350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URL; 360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URLConnection; 370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.security.Principal; 380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.security.cert.Certificate; 39953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.text.DateFormat; 40953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.text.SimpleDateFormat; 410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.ArrayList; 420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Arrays; 430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Collections; 440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Date; 45e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilsonimport java.util.Deque; 460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Iterator; 470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.List; 48953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.util.Locale; 490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Map; 50953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.util.TimeZone; 51433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport java.util.UUID; 520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.TimeUnit; 530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicInteger; 540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicReference; 550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.zip.GZIPOutputStream; 560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.HttpsURLConnection; 570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport junit.framework.TestCase; 580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport libcore.javax.net.ssl.TestSSLContext; 590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport tests.http.MockResponse; 600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport tests.http.MockWebServer; 610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport tests.http.RecordedRequest; 620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport static tests.http.SocketPolicy.DISCONNECT_AT_END; 63e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilsonimport tests.io.MockOs; 640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 65396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilsonpublic final class HttpResponseCacheTest extends TestCase { 66fb4a6392a04b1f3a1124b3db6bae51d8cbfa53f8Jesse Wilson 67fb4a6392a04b1f3a1124b3db6bae51d8cbfa53f8Jesse Wilson // TODO: test cache + cookies 68fb4a6392a04b1f3a1124b3db6bae51d8cbfa53f8Jesse Wilson // TODO: test cache + user-provided Range header 69fb4a6392a04b1f3a1124b3db6bae51d8cbfa53f8Jesse Wilson 700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockWebServer server = new MockWebServer(); 71396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilson private HttpResponseCache cache; 72e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson final MockOs mockOs = new MockOs(); 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(); 820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override protected void tearDown() throws Exception { 85e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.uninstall(); 860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.shutdown(); 87433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson ResponseCache.setDefault(null); 88fb4a6392a04b1f3a1124b3db6bae51d8cbfa53f8Jesse Wilson cache.getCache().delete(); 890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson super.tearDown(); 900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Test that response caching is consistent with the RI and the spec. 940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 9684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testResponseCachingByResponseCode() throws Exception { 970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Test each documented HTTP/1.1 code, plus the first unused value in each range. 980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We can't test 100 because it's not really a response. 1010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // assertCached(false, 100); 1020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 101); 1030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 102); 1040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 200); 1050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 201); 1060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 202); 1070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 203); 1080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 204); 1090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 205); 1100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 206); 1110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 207); 11284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertCached(true, 300); 1130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 301); 1140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 302; i <= 308; ++i) { 1150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 400; i <= 406; ++i) { 1180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // (See test_responseCaching_407.) 1210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 408); 1220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 409); 1230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // (See test_responseCaching_410.) 1240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 411; i <= 418; ++i) { 1250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 500; i <= 506; ++i) { 1280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 1330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Response code 407 should only come from proxy servers. Android's client 1340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * throws if it is sent by an origin server. 1350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testOriginServerSends407() throws Exception { 1370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(407)); 1380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 1410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 1420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson conn.getResponseCode(); 1440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 1450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 1460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_responseCaching_410() throws Exception { 1500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // the HTTP spec permits caching 410s, but the RI doesn't. 15184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertCached(true, 410); 1520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertCached(boolean shouldPut, int responseCode) throws Exception { 1550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server = new MockWebServer(); 1560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 1570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 1590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(responseCode) 1600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABCDE") 1610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("WWW-Authenticate: challenge")); 1620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 1650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 1660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(responseCode, conn.getResponseCode()); 1670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // exhaust the content stream 16984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson readAscii(conn); 1700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 171433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson CacheResponse cached = cache.get(url.toURI(), "GET", 172433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson Collections.<String, List<String>>emptyMap()); 173433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson if (shouldPut) { 174433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson assertNotNull(Integer.toString(responseCode), cached); 175433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson cached.getBody().close(); 176433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } else { 177433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson assertNull(Integer.toString(responseCode), cached); 178433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } 1790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 1800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 1830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Test that we can interrogate the response when the cache is being 1840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * populated. http://code.google.com/p/android/issues/detail?id=7787 1850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCacheCallbackApis() throws Exception { 1870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final String body = "ABCDE"; 1880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final AtomicInteger cacheCount = new AtomicInteger(); 1890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 1910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setStatus("HTTP/1.1 200 Fantastic") 1920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("fgh: ijk") 1930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(body)); 1940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new ResponseCache() { 1970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 1980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 1990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 2000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 2020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection httpConnection = (HttpURLConnection) conn; 203953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson try { 204953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson httpConnection.getRequestProperties(); 205953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail(); 206953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (IllegalStateException expected) { 207953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 208953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson try { 209953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson httpConnection.addRequestProperty("K", "V"); 210953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail(); 211953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (IllegalStateException expected) { 212953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 2130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("HTTP/1.1 200 Fantastic", httpConnection.getHeaderField(null)); 2140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), 2150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson httpConnection.getHeaderFields().get(null)); 2160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, httpConnection.getResponseCode()); 2170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Fantastic", httpConnection.getResponseMessage()); 2180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(body.length(), httpConnection.getContentLength()); 2190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ijk", httpConnection.getHeaderField("fgh")); 2200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 2210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson httpConnection.getInputStream(); // the RI doesn't forbid this, but it should 2220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 2230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 2240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson cacheCount.incrementAndGet(); 2260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 2270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }); 2290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 231953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 2320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(body, readAscii(connection)); 2330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cacheCount.get()); 2340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithFixedLength() throws IOException { 2380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.FIXED_LENGTH); 2390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 2420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.CHUNKED); 2430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 2460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.END_OF_STREAM); 2470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 2500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 2510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://code.google.com/p/android/issues/detail?id=8175 2520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 2530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testResponseCaching(TransferKind transferKind) throws IOException { 2540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse() 2550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 2560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 2570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setStatus("HTTP/1.1 200 Fantastic"); 2580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 2590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Make sure that calling skip() doesn't omit bytes from the cache. 2630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 2640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = urlConnection.getInputStream(); 2650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("I love ", readAscii(urlConnection, "I love ".length())); 2660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson reliableSkip(in, "puppies but hate ".length()); 2670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("spiders", readAscii(urlConnection, "spiders".length())); 2680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(-1, in.read()); 2690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 270ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 271ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteAbortCount()); 2720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); // cached! 2740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in = urlConnection.getInputStream(); 2750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("I love puppies but hate spiders", 2760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(urlConnection, "I love puppies but hate spiders".length())); 2770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, urlConnection.getResponseCode()); 2780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 2790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(-1, in.read()); 281433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson in.close(); 282ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 283ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteAbortCount()); 284ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getRequestCount()); 285ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getHitCount()); 2860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSecureResponseCaching() throws IOException { 2890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 2900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 2910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 2920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 2930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 2940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 2950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 2980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 2990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 3020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String suite = connection.getCipherSuite(); 3030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<Certificate> localCerts = toListOrNull(connection.getLocalCertificates()); 3040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<Certificate> serverCerts = toListOrNull(connection.getServerCertificates()); 3050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Principal peerPrincipal = connection.getPeerPrincipal(); 3060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Principal localPrincipal = connection.getLocalPrincipal(); 3070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached! 3090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 312ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getRequestCount()); 313ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 314ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getHitCount()); 3150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(suite, connection.getCipherSuite()); 3170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(localCerts, toListOrNull(connection.getLocalCertificates())); 3180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(serverCerts, toListOrNull(connection.getServerCertificates())); 3190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(peerPrincipal, connection.getPeerPrincipal()); 3200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(localPrincipal, connection.getLocalPrincipal()); 3210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheReturnsInsecureResponseForSecureRequest() throws IOException { 3240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 3250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 3260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 3270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new InsecureResponseCache()); 3310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 3330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // not cached! 3370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("DEF", readAscii(connection)); 3390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 341a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson public void testResponseCachingAndRedirects() throws Exception { 3420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 3460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /foo")); 3470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 3510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 354953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 3550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 357953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection = server.getUrl("/").openConnection(); // cached! 3580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 360ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects 361ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getNetworkCount()); 362ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 3630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 365a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson public void testRedirectToCachedResult() throws Exception { 366a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse() 367a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .addHeader("Cache-Control: max-age=60") 368a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .setBody("ABC")); 369a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse() 370a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 371a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .addHeader("Location: /foo")); 372a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 373a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.play(); 374a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 375a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("ABC", readAscii(server.getUrl("/foo").openConnection())); 376a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request1 = server.takeRequest(); 377a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /foo HTTP/1.1", request1.getRequestLine()); 378a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(0, request1.getSequenceNumber()); 379a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 380a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("ABC", readAscii(server.getUrl("/bar").openConnection())); 381a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request2 = server.takeRequest(); 382a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /bar HTTP/1.1", request2.getRequestLine()); 383a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(1, request2.getSequenceNumber()); 384a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 385a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson // an unrelated request should reuse the pooled connection 386a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("DEF", readAscii(server.getUrl("/baz").openConnection())); 387a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request3 = server.takeRequest(); 388a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /baz HTTP/1.1", request3.getRequestLine()); 389a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(2, request3.getSequenceNumber()); 390a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } 391a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 3920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSecureResponseCachingAndRedirects() throws IOException { 3930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 3940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 3950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 3990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /foo")); 4000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 4010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 4020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 4030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 4040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 4050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 4080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 4100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached! 4120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 4140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 415ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 416ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 4170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCacheRequestHeaders() throws IOException, URISyntaxException { 4200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 4210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final AtomicReference<Map<String, List<String>>> requestHeadersRef 4240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson = new AtomicReference<Map<String, List<String>>>(); 4250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new ResponseCache() { 4260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 4270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 4280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestHeadersRef.set(requestHeaders); 4290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 4300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 4320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 4330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }); 4350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 4370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection urlConnection = url.openConnection(); 4380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("A", "android"); 4390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(urlConnection); 4400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("android"), requestHeadersRef.get().get("A")); 4410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 4450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 4460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 4490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.CHUNKED); 4500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 4530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 4540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Intentionally empty. This case doesn't make sense because there's no 4550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * such thing as a premature disconnect when the disconnect itself 4560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * indicates the end of the data stream. 4570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 4580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 4610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 4620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 4630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(truncateViolently(response, 16)); 4640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 4650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson BufferedReader reader = new BufferedReader(new InputStreamReader( 4680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.getUrl("/").openConnection().getInputStream())); 4690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", reader.readLine()); 4700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson reader.readLine(); 4720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("This implementation silently ignored a truncated HTTP body."); 4730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 474433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } finally { 475433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson reader.close(); 4760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 478ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 479ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteSuccessCount()); 4800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 4810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Request #2", readAscii(connection)); 482ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 483ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 4840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithContentLengthHeader() throws IOException { 4870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 4880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithChunkedEncoding() throws IOException { 4910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.CHUNKED); 4920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithNoLengthHeaders() throws IOException { 4950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 4960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 4990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 5000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 5010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 5020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 5030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 5040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 5060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = connection.getInputStream(); 5070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", readAscii(connection, 5)); 5080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 5090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 5100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.read(); 5110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Expected an IOException because the stream is closed."); 5120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 5130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 515ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 516ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getWriteSuccessCount()); 5170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = server.getUrl("/").openConnection(); 51884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("Request #2", readAscii(connection)); 519ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteAbortCount()); 520ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getWriteSuccessCount()); 5210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 523953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 52421dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 105 seconds ago 52521dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 5 seconds ago 52621dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (105 - 5) / 10 = 10 seconds 52721dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds from now 528953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 52921dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 530953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 531953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 532953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 533953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 534953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URL url = server.getUrl("/"); 535953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 536953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 537953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 538953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertNull(connection.getHeaderField("Warning")); 53921dddca4064527116af7a1553de502c6d11138daJesse Wilson } 54021dddca4064527116af7a1553de502c6d11138daJesse Wilson 54121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testDefaultExpirationDateConditionallyCached() throws Exception { 54221dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 115 seconds ago 54321dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 15 seconds ago 54421dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (115 - 15) / 10 = 10 seconds 54521dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds ago 54621dddca4064527116af7a1553de502c6d11138daJesse Wilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 5470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 54821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 54921dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 5500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 554953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 555953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // last modified: 105 days ago 556953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // served: 5 days ago 557953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // default lifetime: (105 - 5) / 10 = 10 days 558953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // expires: 10 days from served date = 5 days from now 559953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 560953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 561953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 562953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 563953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 564953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 565953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 566953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 567953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 568953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 569953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 570953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 571953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 57221dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testNoDefaultExpirationForUrlsWithQueryString() throws Exception { 57321dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 57421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 57521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 57621dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 57721dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 57821dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 57921dddca4064527116af7a1553de502c6d11138daJesse Wilson 58021dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/?foo=bar"); 58121dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(url.openConnection())); 58221dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 58321dddca4064527116af7a1553de502c6d11138daJesse Wilson } 58421dddca4064527116af7a1553de502c6d11138daJesse Wilson 5850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithLastModifiedHeader() throws Exception { 5860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 5870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 5880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 5890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 5900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithNoLastModifiedHeader() throws Exception { 5950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 5960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 5970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInTheFuture() throws Exception { 6000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 6020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgePreferredWithMaxAgeAndExpires() throws Exception { 6050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 6070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 6080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 6120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 6130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 6140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 6150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 6160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 6180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 6190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 62284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson /* 62384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * Chrome interprets max-age relative to the local clock. Both our cache 62484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * and Firefox both use the earlier of the local and server's clock. 62584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson */ 6260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 6270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 6280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithDateHeader() throws Exception { 6320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 6340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithNoDateHeader() throws Exception { 6380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 642adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeWithLastModifiedButNoServedDate() throws Exception { 643adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 644adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 645adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 646adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 647adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 648adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 649adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 650adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 651adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 652adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 653adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 654adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 65521dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverLowerSharedMaxAge() throws Exception { 65621dddca4064527116af7a1553de502c6d11138daJesse Wilson assertFullyCached(new MockResponse() 65721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 65821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60") 65921dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=180")); 66021dddca4064527116af7a1553de502c6d11138daJesse Wilson } 66121dddca4064527116af7a1553de502c6d11138daJesse Wilson 66221dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverHigherMaxAge() throws Exception { 66321dddca4064527116af7a1553de502c6d11138daJesse Wilson assertNotCached(new MockResponse() 66421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 66521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=180") 66621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60")); 66721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 66821dddca4064527116af7a1553de502c6d11138daJesse Wilson 6690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodOptionsIsNotCached() throws Exception { 6700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("OPTIONS", false); 6710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodGetIsCached() throws Exception { 6740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("GET", true); 6750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodHeadIsNotCached() throws Exception { 6780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("HEAD", false); 6800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPostIsNotCached() throws Exception { 6830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("POST", false); 6850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPutIsNotCached() throws Exception { 6880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("PUT", false); 6890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodDeleteIsNotCached() throws Exception { 6920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("DELETE", false); 6930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodTraceIsNotCached() throws Exception { 6960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("TRACE", false); 6970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 7000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 7010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache (potentially) 7020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. expect a cache hit or miss 7030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 7050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 1")); 7070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 7080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 2")); 7090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection request1 = (HttpURLConnection) url.openConnection(); 7140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson request1.setRequestMethod(requestMethod); 7150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, request1); 7160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 7170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 718953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection request2 = url.openConnection(); 7190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (expectCached) { 7200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 7210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } else { 7220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 7230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPostInvalidatesCache() throws Exception { 7270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("POST"); 7280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPutInvalidatesCache() throws Exception { 7310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("PUT"); 7320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testDeleteMethodInvalidatesCache() throws Exception { 7350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("DELETE"); 7360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testMethodInvalidates(String requestMethod) throws Exception { 7390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 7400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache 7410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. invalidate it 7420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 3. expect a cache miss 7430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 7450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 7460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 7470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("C")); 7480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 7530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection invalidate = (HttpURLConnection) url.openConnection(); 7550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setRequestMethod(requestMethod); 7560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, invalidate); 7570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(invalidate)); 7580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("C", readAscii(url.openConnection())); 7600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtag() throws Exception { 7630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1")); 7650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1")); 7660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInThePast() throws Exception { 7690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 7740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 7760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInTheFuture() throws Exception { 7800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 7810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 7830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 7840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCache() throws Exception { 7870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 7880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 7910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-cache")); 7960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCache() throws Exception { 8010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 8020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 8050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 8060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 8070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 8080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Pragma: no-cache")); 8100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 8110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 8120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStore() throws Exception { 8150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 8160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 8190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 8200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-store")); 8230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPartialRangeResponsesDoNotCorruptCache() throws Exception { 8260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 8270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. request a range 8280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. request a full document, expecting a cache miss 8290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 8300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("AA") 8310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 8320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Range: bytes 1000-1001/2000")); 8340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("BB")); 8350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 8380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection range = url.openConnection(); 8400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson range.addRequestProperty("Range", "bytes=1000-1001"); 8410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("AA", readAscii(range)); 8420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("BB", readAscii(url.openConnection())); 8440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerReturnsDocumentOlderThanCache() throws Exception { 8470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 8480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B") 8510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 8520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 8550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndConditionalCache() throws Exception { 8610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndFullCache() throws Exception { 8670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 8700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 8730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response 8740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(gzip("ABCABCABC".getBytes("UTF-8"))) 8750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Encoding: gzip")); 8760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 8770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpiresDateBeforeModifiedDate() throws Exception { 8840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertConditionallyCached(new MockResponse() 8850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 8860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 8870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 889adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMaxAge() throws IOException { 890adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 891adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 892adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 893adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 894adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 895adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 896adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 897adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 898adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 899adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 900adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "max-age=30"); 901adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 902adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 903adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 904adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMinFresh() throws IOException { 905adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 906adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60") 907adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 908adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 909adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 910adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 911adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 912adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 913adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 914adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 915adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 916adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 917adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 918c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestMaxStale() throws IOException { 919c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 920c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=120") 921c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 922c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("B")); 923c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 924c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 925c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 926c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 927c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 928c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 929c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(connection)); 930953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("110 HttpURLConnection \"Response is stale\"", 931953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 932c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 933c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 9342f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson public void testRequestMaxStaleNotHonoredWithMustRevalidate() throws IOException { 9352f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setBody("A") 9362f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Cache-Control: max-age=120, must-revalidate") 9372f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 9382f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 9392f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 9402f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.play(); 9412f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 9422f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 9432f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 9442f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 9452f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("B", readAscii(connection)); 9462f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 9472f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 948c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithNoResponseCached() throws IOException { 949c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson // (no responses enqueued) 950c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 951c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 952953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 953c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 954c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 955c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 956c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 957c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithFullResponseCached() throws IOException { 958c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 959c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 960c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 961c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 962c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 963c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 964c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 965c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 966c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 967c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 968c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 969c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithConditionalResponseCached() throws IOException { 970c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 971c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 972c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 973c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 974c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 975c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 976953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 977c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 978c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 979c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 980c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 981c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 982c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A")); 983c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 984c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 985c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 986953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 987c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 988c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 989c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 990c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 99184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestCacheControlNoCache() throws Exception { 99284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 99384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 99484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 99584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 99684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 99784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 99884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 99984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 100084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 100184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 100284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 100384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Cache-Control", "no-cache"); 100484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 100584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 100684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 100784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestPragmaNoCache() throws Exception { 100884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 100984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 101084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 101184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 101284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 101384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 101484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 101584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 101684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 101784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 101884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 101984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Pragma", "no-cache"); 102084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 102184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 102284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 102384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 102484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 102584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("ETag: v3") 102684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 102784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 102884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 102984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-Modified-Since", ifModifiedSinceDate); 103084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 103184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate)); 103284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-None-Match: v3")); 103384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 103484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 103584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 103684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 103784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 103884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 103984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 104084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 104184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 104284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-None-Match", "v1"); 104384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 104484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 104584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate)); 104684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 104784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 104884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 104984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String conditionValue) throws Exception { 105084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(seed.setBody("A")); 105184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 105284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 105384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 105484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 105584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 105684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 105784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 105884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty(conditionName, conditionValue); 105984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 106084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 106184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 106284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.takeRequest(); // seed 106384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson return server.takeRequest(); 106484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 106584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 10669531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson public void testSetIfModifiedSince() throws Exception { 10679531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson Date since = new Date(); 10689531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson server.enqueue(new MockResponse().setBody("A")); 10699531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson server.play(); 10709531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 10719531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson URL url = server.getUrl("/"); 10729531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson URLConnection connection = url.openConnection(); 10739531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson connection.setIfModifiedSince(since.getTime()); 10749531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson assertEquals("A", readAscii(connection)); 10759531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson RecordedRequest request = server.takeRequest(); 10769531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson assertTrue(request.getHeaders().contains("If-Modified-Since: " + formatDate(since))); 10779531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 10789531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 107984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedConditionWithoutCachedResult() throws Exception { 108084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 108184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 108284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 108384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 108484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 108584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 108684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 108784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 108884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 108984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 1090c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 109121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationRequestHeaderPreventsCaching() throws Exception { 109221dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 109321dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES)) 109421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60") 109521dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 109621dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 109721dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 109821dddca4064527116af7a1553de502c6d11138daJesse Wilson 109921dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/"); 1100953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 110121dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.addRequestProperty("Authorization", "password"); 110221dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(connection)); 110321dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 110421dddca4064527116af7a1553de502c6d11138daJesse Wilson } 110521dddca4064527116af7a1553de502c6d11138daJesse Wilson 110621dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithSMaxAge() throws Exception { 110721dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 110821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60")); 110921dddca4064527116af7a1553de502c6d11138daJesse Wilson } 111021dddca4064527116af7a1553de502c6d11138daJesse Wilson 111121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithPublic() throws Exception { 111221dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 111321dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: public")); 111421dddca4064527116af7a1553de502c6d11138daJesse Wilson } 111521dddca4064527116af7a1553de502c6d11138daJesse Wilson 111621dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithMustRevalidate() throws Exception { 111721dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 111821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: must-revalidate")); 111921dddca4064527116af7a1553de502c6d11138daJesse Wilson } 112021dddca4064527116af7a1553de502c6d11138daJesse Wilson 112121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception { 112221dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(response 112321dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60") 112421dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 112521dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 112621dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 112721dddca4064527116af7a1553de502c6d11138daJesse Wilson 112821dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/"); 1129953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 113021dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.addRequestProperty("Authorization", "password"); 113121dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(connection)); 113221dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(url.openConnection())); 113321dddca4064527116af7a1553de502c6d11138daJesse Wilson } 113421dddca4064527116af7a1553de502c6d11138daJesse Wilson 1135953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testContentLocationDoesNotPopulateCache() throws Exception { 1136953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 1137953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Cache-Control: max-age=60") 1138953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Content-Location: /bar") 1139953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 1140953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1141953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 1142953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1143953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/foo").openConnection())); 1144953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("B", readAscii(server.getUrl("/bar").openConnection())); 1145953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1146953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 114719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testUseCachesFalseDoesNotWriteToCache() throws Exception { 114819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse() 114919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .addHeader("Cache-Control: max-age=60") 115019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .setBody("A").setBody("A")); 115119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 115219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.play(); 115319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 115419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 115519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson connection.setUseCaches(false); 115619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("A", readAscii(connection)); 115719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 115819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 115919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 116019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testUseCachesFalseDoesNotReadFromCache() throws Exception { 116119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse() 116219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .addHeader("Cache-Control: max-age=60") 116319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .setBody("A").setBody("A")); 116419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 116519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.play(); 116619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 116719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 116819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 116919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson connection.setUseCaches(false); 117019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("B", readAscii(connection)); 117119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 117219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 117319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testDefaultUseCachesSetsInitialValueOnly() throws Exception { 117419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URL url = new URL("http://localhost/"); 117519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection c1 = url.openConnection(); 117619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection c2 = url.openConnection(); 117719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertTrue(c1.getDefaultUseCaches()); 117819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson c1.setDefaultUseCaches(false); 117919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson try { 118019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertTrue(c1.getUseCaches()); 118119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertTrue(c2.getUseCaches()); 118219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection c3 = url.openConnection(); 118319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertFalse(c3.getUseCaches()); 118419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } finally { 118519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson c1.setDefaultUseCaches(true); 118619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 118719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 118819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 11892f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson public void testConnectionIsReturnedToPoolAfterConditionalSuccess() throws Exception { 11902f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse() 11912f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 11922f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Cache-Control: max-age=0") 11932f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .setBody("A")); 11942f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 11952f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 11962f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.play(); 11972f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 11982f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/a").openConnection())); 11992f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/a").openConnection())); 12002f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("B", readAscii(server.getUrl("/b").openConnection())); 12012f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 12022f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 12032f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 12042f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals(2, server.takeRequest().getSequenceNumber()); 12052f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 12062f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 1207757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testStatisticsConditionalCacheMiss() throws Exception { 1208757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1209757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1210757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Cache-Control: max-age=0") 1211757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setBody("A")); 1212757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setBody("B")); 1213757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setBody("C")); 1214757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.play(); 1215757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1216757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1217ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getRequestCount()); 1218ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1219ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1220757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 1221757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("C", readAscii(server.getUrl("/").openConnection())); 1222ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getRequestCount()); 1223ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getNetworkCount()); 1224ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1225757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1226757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1227757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testStatisticsConditionalCacheHit() throws Exception { 1228757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1229757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1230757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Cache-Control: max-age=0") 1231757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setBody("A")); 1232757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1233757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1234757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.play(); 1235757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1236757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1237ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getRequestCount()); 1238ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1239ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1240757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1241757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1242ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getRequestCount()); 1243ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getNetworkCount()); 1244ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 1245757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1246757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1247757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testStatisticsFullCacheHit() throws Exception { 1248757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1249757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Cache-Control: max-age=60") 1250757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setBody("A")); 1251757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.play(); 1252757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1253757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1254ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getRequestCount()); 1255ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1256ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(0, cache.getHitCount()); 1257757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1258757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 1259ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(3, cache.getRequestCount()); 1260ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, cache.getNetworkCount()); 1261ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, cache.getHitCount()); 1262757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1263757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 12646f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesChangedRequestHeaderField() throws Exception { 12656f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 12666f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 12676f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 12686f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 12696f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 12706f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 12716f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12726f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 12736f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpURLConnection frConnection = (HttpURLConnection) url.openConnection(); 12746f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 12756f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(frConnection)); 12766f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12776f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpURLConnection enConnection = (HttpURLConnection) url.openConnection(); 12786f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Language", "en-US"); 12796f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(enConnection)); 12806f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 12816f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12826f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesUnchangedRequestHeaderField() throws Exception { 12836f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 12846f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 12856f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 12866f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 12876f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 12886f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 12896f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12906f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 12916f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 12926f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 12936f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 12946f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 12956f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 12966f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 12976f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 12986f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 12996f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesAbsentRequestHeaderField() throws Exception { 13006f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13016f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13026f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Foo") 13036f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13046f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13056f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13066f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13076f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 13086f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 13096f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13106f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13116f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesAddedRequestHeaderField() throws Exception { 13126f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13136f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13146f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Foo") 13156f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13166f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13176f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13186f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13196f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 13206f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection fooConnection = server.getUrl("/").openConnection(); 13216f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson fooConnection.addRequestProperty("Foo", "bar"); 13226f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(fooConnection)); 13236f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13246f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13256f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMatchesRemovedRequestHeaderField() throws Exception { 13266f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13276f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13286f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Foo") 13296f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13306f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13316f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13326f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13336f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection fooConnection = server.getUrl("/").openConnection(); 13346f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson fooConnection.addRequestProperty("Foo", "bar"); 13356f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(fooConnection)); 13366f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 13376f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13386f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13396f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryFieldsAreCaseInsensitive() throws Exception { 13406f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13416f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13426f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: ACCEPT-LANGUAGE") 13436f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13446f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13456f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13466f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13476f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 13486f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 13496f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 13506f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 13516f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 13526f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("accept-language", "fr-CA"); 13536f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 13546f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13556f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13566f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldsWithMatch() throws Exception { 13576f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13586f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13596f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language, Accept-Charset") 13606f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Encoding") 13616f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13626f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13636f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13646f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13656f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 13666f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 13676f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 13686f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Charset", "UTF-8"); 13696f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Encoding", "identity"); 13706f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 13716f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 13726f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 13736f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Charset", "UTF-8"); 13746f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Encoding", "identity"); 13756f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 13766f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13776f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13786f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldsWithNoMatch() throws Exception { 13796f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 13806f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 13816f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language, Accept-Charset") 13826f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Encoding") 13836f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 13846f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 13856f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 13866f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 13876f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 13886f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection frConnection = url.openConnection(); 13896f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 13906f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Charset", "UTF-8"); 13916f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson frConnection.addRequestProperty("Accept-Encoding", "identity"); 13926f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(frConnection)); 13936f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection enConnection = url.openConnection(); 13946f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Language", "en-CA"); 13956f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Charset", "UTF-8"); 13966f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson enConnection.addRequestProperty("Accept-Encoding", "identity"); 13976f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(enConnection)); 13986f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 13996f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14006f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldValuesWithMatch() throws Exception { 14016f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14026f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14036f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 14046f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14056f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14066f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14076f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14086f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 14096f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 14106f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 14116f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "en-US"); 14126f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 14136f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14146f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 14156f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 14166f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "en-US"); 14176f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 14186f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14196f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14206f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryMultipleFieldValuesWithNoMatch() throws Exception { 14216f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14226f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14236f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 14246f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14256f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14266f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14276f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14286f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 14296f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection1 = url.openConnection(); 14306f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 14316f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "en-US"); 14326f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 14336f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14346f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URLConnection connection2 = url.openConnection(); 14356f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 14366f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "en-US"); 14376f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(connection2)); 14386f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14396f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14406f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryAsterisk() throws Exception { 14416f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14426f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14436f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: *") 14446f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14456f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14466f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14476f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14486f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 14496f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("B", readAscii(server.getUrl("/").openConnection())); 14506f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14516f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14526f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson public void testVaryAndHttps() throws Exception { 14536f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 14546f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 14556f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse() 14566f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Cache-Control: max-age=60") 14576f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .addHeader("Vary: Accept-Language") 14586f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson .setBody("A")); 14596f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.enqueue(new MockResponse().setBody("B")); 14606f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson server.play(); 14616f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14626f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson URL url = server.getUrl("/"); 14636f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpsURLConnection connection1 = (HttpsURLConnection) url.openConnection(); 14646f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 14656f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection1.addRequestProperty("Accept-Language", "en-US"); 14666f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection1)); 14676f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 14686f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson HttpsURLConnection connection2 = (HttpsURLConnection) url.openConnection(); 14696f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 14706f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson connection2.addRequestProperty("Accept-Language", "en-US"); 14716f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson assertEquals("A", readAscii(connection2)); 14726f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson } 14736f778cc173cc60ec184e8ca54a16ad10cf55f2cfJesse Wilson 1474e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson public void testDiskWriteFailureCacheDegradation() throws Exception { 1475e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson Deque<InvocationHandler> writeHandlers = mockOs.getHandlers("write"); 1476e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson int i = 0; 1477e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson boolean hasMoreScenarios = true; 1478e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson while (hasMoreScenarios) { 1479e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueNormal("write", i++); 1480e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueFault("write"); 1481e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson exercisePossiblyFaultyCache(false); 1482e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson hasMoreScenarios = writeHandlers.isEmpty(); 1483e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson writeHandlers.clear(); 1484e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1485e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson System.out.println("Exercising the cache performs " + (i - 1) + " writes."); 1486e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1487e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 1488e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson public void testDiskReadFailureCacheDegradation() throws Exception { 1489e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson Deque<InvocationHandler> readHandlers = mockOs.getHandlers("read"); 1490e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson int i = 0; 1491e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson boolean hasMoreScenarios = true; 1492e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson while (hasMoreScenarios) { 1493e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueNormal("read", i++); 1494e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson mockOs.enqueueFault("read"); 1495e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson exercisePossiblyFaultyCache(true); 1496e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson hasMoreScenarios = readHandlers.isEmpty(); 1497e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson readHandlers.clear(); 1498e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1499e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson System.out.println("Exercising the cache performs " + (i - 1) + " reads."); 1500e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1501e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 15020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 15030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @param delta the offset from the current date to use. Negative 15040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * values yield dates in the past; positive values yield dates in the 15050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * future. 15060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1507953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private String formatDate(long delta, TimeUnit timeUnit) { 15089531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta))); 15099531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 15109531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 15119531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson private String formatDate(Date date) { 1512953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 1513953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson rfc1123.setTimeZone(TimeZone.getTimeZone("UTC")); 1514953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson return rfc1123.format(date); 15150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 15160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 15180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 15190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 15200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setDoOutput(true); 15210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream requestBody = invalidate.getOutputStream(); 15220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.write('x'); 15230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.close(); 15240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 15250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 15260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNotCached(MockResponse response) throws Exception { 15280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 15290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 15300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 15310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 15330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 15340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(url.openConnection())); 15350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 15360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1537e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson private void exercisePossiblyFaultyCache(boolean permitReadBodyFailures) throws Exception { 1538e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.shutdown(); 1539e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server = new MockWebServer(); 1540e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.enqueue(new MockResponse() 1541e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson .addHeader("Cache-Control: max-age=60") 1542e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson .setBody("A")); 1543e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1544e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson server.play(); 1545e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 1546e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson URL url = server.getUrl("/" + UUID.randomUUID()); 1547e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 1548e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 1549e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson URLConnection connection = url.openConnection(); 1550e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson InputStream in = connection.getInputStream(); 1551e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson try { 1552e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson int bodyChar = in.read(); 1553e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson assertTrue(bodyChar == 'A' || bodyChar == 'B'); 1554e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson assertEquals(-1, in.read()); 1555e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } catch (IOException e) { 1556e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson if (!permitReadBodyFailures) { 1557e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson throw e; 1558e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1559e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1560e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson } 1561e5eb80e6adaab18ff7372adcd09f9e1af3a76871Jesse Wilson 15620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 15630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @return the request with the conditional get headers. 15640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 15650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 15660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 1: condition succeeds 15670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 15680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 15690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 2: condition fails 15710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("B")); 15720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("C")); 15730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 15750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL valid = server.getUrl("/valid"); 15770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(valid.openConnection())); 15780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(valid.openConnection())); 15790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL invalid = server.getUrl("/invalid"); 15810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(invalid.openConnection())); 15820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("C", readAscii(invalid.openConnection())); 15830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.takeRequest(); // regular get 15850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return server.takeRequest(); // conditional get 15860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 15870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertFullyCached(MockResponse response) throws Exception { 15890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 15900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("B")); 15910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 15920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 15940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 15950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 15960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 15970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 15980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 15990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Shortens the body of {@code response} but not the corresponding headers. 16000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Only useful to test how clients respond to the premature conclusion of 16010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * the HTTP body. 16020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 16030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 16040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 16050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = new ArrayList<String>(response.getHeaders()); 16060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 16070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().clear(); 16080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().addAll(headers); 16090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 16100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 16130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Reads {@code count} characters from the stream. If the stream is 16140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * exhausted before {@code count} characters can be read, the remaining 16150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * characters are returned and the stream is closed. 16160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 16170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection, int count) throws IOException { 161884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 161984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 162084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson ? connection.getInputStream() 162184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson : httpConnection.getErrorStream(); 16220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson StringBuilder result = new StringBuilder(); 16230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 0; i < count; i++) { 16240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson int value = in.read(); 16250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (value == -1) { 16260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 16270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 16280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson result.append((char) value); 16300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return result.toString(); 16320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection) throws IOException { 16350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return readAscii(connection, Integer.MAX_VALUE); 16360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void reliableSkip(InputStream in, int length) throws IOException { 16390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson while (length > 0) { 16400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson length -= in.skip(length); 16410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1644953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private void assertBadGateway(HttpURLConnection connection) throws IOException { 1645c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson try { 1646c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.getInputStream(); 1647c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson fail(); 1648c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } catch (FileNotFoundException expected) { 1649c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1650953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(HttpURLConnection.HTTP_BAD_GATEWAY, connection.getResponseCode()); 1651953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(-1, connection.getErrorStream().read()); 1652c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1653c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 16540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson enum TransferKind { 16550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson CHUNKED() { 16560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) 16570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 16580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setChunkedBody(content, chunkSize); 16590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 16610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson FIXED_LENGTH() { 16620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 16630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 16640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 16660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson END_OF_STREAM() { 16670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 16680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 16690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 16700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 16710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (h.next().startsWith("Content-Length:")) { 16720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson h.remove(); 16730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 16740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 16780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson abstract void setBody(MockResponse response, byte[] content, int chunkSize) 16800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException; 16810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 16830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson setBody(response, content.getBytes("UTF-8"), chunkSize); 16840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 16880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 16890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 16900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 16910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 16920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Returns a gzipped copy of {@code bytes}. 16930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 16940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public byte[] gzip(byte[] bytes) throws IOException { 16950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 16960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 16970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.write(bytes); 16980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.close(); 16990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return bytesOut.toByteArray(); 17000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1702433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson private class InsecureResponseCache extends ResponseCache { 17030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 1704433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson return cache.put(uri, connection); 17050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 17080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 1709433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson final CacheResponse response = cache.get(uri, requestMethod, requestHeaders); 17100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (response instanceof SecureCacheResponse) { 17110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return new CacheResponse() { 17120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public InputStream getBody() throws IOException { 17130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getBody(); 17140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public Map<String, List<String>> getHeaders() throws IOException { 17160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getHeaders(); 17170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 17190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 17210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 17230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson} 1724