HttpResponseCacheTest.java revision a4193d7e636802a2705ffb52cb69c69ff59bfbb2
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 170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonpackage libcore.java.net; 180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.BufferedReader; 200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.ByteArrayOutputStream; 21c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilsonimport java.io.FileNotFoundException; 220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.IOException; 230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.InputStream; 240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.InputStreamReader; 250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.OutputStream; 260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheRequest; 270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheResponse; 280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.HttpURLConnection; 290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.ResponseCache; 300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.SecureCacheResponse; 310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URI; 320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URISyntaxException; 330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URL; 340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URLConnection; 350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.security.Principal; 360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.security.cert.Certificate; 37953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.text.DateFormat; 38953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.text.SimpleDateFormat; 390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.ArrayList; 400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Arrays; 410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Collections; 420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Date; 430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Iterator; 440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.List; 45953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.util.Locale; 460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Map; 470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Set; 48953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.util.TimeZone; 490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.TimeUnit; 500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicInteger; 510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicReference; 520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.zip.GZIPOutputStream; 530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.HttpsURLConnection; 540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport junit.framework.TestCase; 550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport libcore.javax.net.ssl.TestSSLContext; 560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport libcore.net.http.HttpResponseCache; 570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport tests.http.MockResponse; 580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport tests.http.MockWebServer; 590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport tests.http.RecordedRequest; 600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport static tests.http.SocketPolicy.DISCONNECT_AT_END; 610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonpublic final class HttpResponseCacheTest extends TestCase { 630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockWebServer server = new MockWebServer(); 640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private HttpResponseCache cache = new HttpResponseCache(); 650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override protected void setUp() throws Exception { 670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson super.setUp(); 680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(cache); 690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override protected void tearDown() throws Exception { 720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(null); 730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.shutdown(); 740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson super.tearDown(); 750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Test that response caching is consistent with the RI and the spec. 790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 8184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testResponseCachingByResponseCode() throws Exception { 820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Test each documented HTTP/1.1 code, plus the first unused value in each range. 830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We can't test 100 because it's not really a response. 860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // assertCached(false, 100); 870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 101); 880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 102); 890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 200); 900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 201); 910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 202); 920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 203); 930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 204); 940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 205); 950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 206); 960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 207); 9784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertCached(true, 300); 980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(true, 301); 990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 302; i <= 308; ++i) { 1000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 400; i <= 406; ++i) { 1030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // (See test_responseCaching_407.) 1060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 408); 1070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, 409); 1080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // (See test_responseCaching_410.) 1090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 411; i <= 418; ++i) { 1100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 500; i <= 506; ++i) { 1130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertCached(false, i); 1140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 1180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Response code 407 should only come from proxy servers. Android's client 1190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * throws if it is sent by an origin server. 1200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testOriginServerSends407() throws Exception { 1220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(407)); 1230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 1260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 1270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson conn.getResponseCode(); 1290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 1300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 1310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_responseCaching_410() throws Exception { 1350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // the HTTP spec permits caching 410s, but the RI doesn't. 13684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertCached(true, 410); 1370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertCached(boolean shouldPut, int responseCode) throws Exception { 1400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server = new MockWebServer(); 1410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 1420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 1430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 1440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(responseCode) 1450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABCDE") 1460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("WWW-Authenticate: challenge")); 1470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 1500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 1510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(responseCode, conn.getResponseCode()); 1520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // exhaust the content stream 15484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson readAscii(conn); 1550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Set<URI> expectedCachedUris = shouldPut 1570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ? Collections.singleton(url.toURI()) 1580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson : Collections.<URI>emptySet(); 1590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Integer.toString(responseCode), 1600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson expectedCachedUris, cache.getContents().keySet()); 1610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 1620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 1650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Test that we can interrogate the response when the cache is being 1660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * populated. http://code.google.com/p/android/issues/detail?id=7787 1670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCacheCallbackApis() throws Exception { 1690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final String body = "ABCDE"; 1700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final AtomicInteger cacheCount = new AtomicInteger(); 1710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 1730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setStatus("HTTP/1.1 200 Fantastic") 1740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("fgh: ijk") 1750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(body)); 1760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new ResponseCache() { 1790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 1800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 1810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 1820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 1840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection httpConnection = (HttpURLConnection) conn; 185953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson try { 186953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson httpConnection.getRequestProperties(); 187953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail(); 188953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (IllegalStateException expected) { 189953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 190953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson try { 191953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson httpConnection.addRequestProperty("K", "V"); 192953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail(); 193953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (IllegalStateException expected) { 194953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("HTTP/1.1 200 Fantastic", httpConnection.getHeaderField(null)); 1960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), 1970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson httpConnection.getHeaderFields().get(null)); 1980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, httpConnection.getResponseCode()); 1990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Fantastic", httpConnection.getResponseMessage()); 2000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(body.length(), httpConnection.getContentLength()); 2010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ijk", httpConnection.getHeaderField("fgh")); 2020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 2030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson httpConnection.getInputStream(); // the RI doesn't forbid this, but it should 2040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 2050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 2060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson cacheCount.incrementAndGet(); 2080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 2090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }); 2110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 213953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 2140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(body, readAscii(connection)); 2150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cacheCount.get()); 2160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithFixedLength() throws IOException { 2200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.FIXED_LENGTH); 2210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 2240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.CHUNKED); 2250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 2280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseCaching(TransferKind.END_OF_STREAM); 2290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 2320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 2330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://code.google.com/p/android/issues/detail?id=8175 2340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 2350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testResponseCaching(TransferKind transferKind) throws IOException { 2360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse() 2370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 2380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 2390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setStatus("HTTP/1.1 200 Fantastic"); 2400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 2410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Make sure that calling skip() doesn't omit bytes from the cache. 2450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 2460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = urlConnection.getInputStream(); 2470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("I love ", readAscii(urlConnection, "I love ".length())); 2480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson reliableSkip(in, "puppies but hate ".length()); 2490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("spiders", readAscii(urlConnection, "spiders".length())); 2500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(-1, in.read()); 2510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 2520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getSuccessCount()); 2530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, cache.getAbortCount()); 2540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); // cached! 2560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in = urlConnection.getInputStream(); 2570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("I love puppies but hate spiders", 2580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(urlConnection, "I love puppies but hate spiders".length())); 2590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, urlConnection.getResponseCode()); 2600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 2610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(-1, in.read()); 2630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getMissCount()); 2640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getHitCount()); 2650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getSuccessCount()); 2660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, cache.getAbortCount()); 2670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSecureResponseCaching() throws IOException { 2700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 2710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 2720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 2730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 2740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 2750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 2760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 2790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 2800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 2810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 2830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String suite = connection.getCipherSuite(); 2840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<Certificate> localCerts = toListOrNull(connection.getLocalCertificates()); 2850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<Certificate> serverCerts = toListOrNull(connection.getServerCertificates()); 2860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Principal peerPrincipal = connection.getPeerPrincipal(); 2870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Principal localPrincipal = connection.getLocalPrincipal(); 2880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached! 2900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 2910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 2920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getMissCount()); 2940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getHitCount()); 2950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(suite, connection.getCipherSuite()); 2970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(localCerts, toListOrNull(connection.getLocalCertificates())); 2980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(serverCerts, toListOrNull(connection.getServerCertificates())); 2990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(peerPrincipal, connection.getPeerPrincipal()); 3000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(localPrincipal, connection.getLocalPrincipal()); 3010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheReturnsInsecureResponseForSecureRequest() throws IOException { 3040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 3050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 3060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 3070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new InsecureResponseCache()); 3110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 3130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // not cached! 3170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("DEF", readAscii(connection)); 3190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 321a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson public void testResponseCachingAndRedirects() throws Exception { 3220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 3260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /foo")); 3270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 3310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 334953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 3350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 337953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection = server.getUrl("/").openConnection(); // cached! 3380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(2, cache.getMissCount()); // 1 redirect + 1 final response = 2 3410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(2, cache.getHitCount()); 3420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 344a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson public void testRedirectToCachedResult() throws Exception { 345a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse() 346a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .addHeader("Cache-Control: max-age=60") 347a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .setBody("ABC")); 348a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse() 349a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 350a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .addHeader("Location: /foo")); 351a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 352a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.play(); 353a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 354a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("ABC", readAscii(server.getUrl("/foo").openConnection())); 355a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request1 = server.takeRequest(); 356a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /foo HTTP/1.1", request1.getRequestLine()); 357a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(0, request1.getSequenceNumber()); 358a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 359a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("ABC", readAscii(server.getUrl("/bar").openConnection())); 360a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request2 = server.takeRequest(); 361a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /bar HTTP/1.1", request2.getRequestLine()); 362a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(1, request2.getSequenceNumber()); 363a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 364a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson // an unrelated request should reuse the pooled connection 365a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("DEF", readAscii(server.getUrl("/baz").openConnection())); 366a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request3 = server.takeRequest(); 367a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("GET /baz HTTP/1.1", request3.getRequestLine()); 368a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(2, request3.getSequenceNumber()); 369a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } 370a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 371a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson // TODO: test connection is returned to pool after conditional success 372a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 3730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSecureResponseCachingAndRedirects() throws IOException { 3740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 3750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 3760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 3800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /foo")); 3810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 3850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 3890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached! 3930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(2, cache.getMissCount()); // 1 redirect + 1 final response = 2 3970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(2, cache.getHitCount()); 3980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCacheRequestHeaders() throws IOException, URISyntaxException { 4010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 4020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final AtomicReference<Map<String, List<String>>> requestHeadersRef 4050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson = new AtomicReference<Map<String, List<String>>>(); 4060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new ResponseCache() { 4070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 4080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 4090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestHeadersRef.set(requestHeaders); 4100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 4110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 4130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 4140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }); 4160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 4180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection urlConnection = url.openConnection(); 4190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("A", "android"); 4200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(urlConnection); 4210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("android"), requestHeadersRef.get().get("A")); 4220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 4260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 4270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 4300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.CHUNKED); 4310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 4340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 4350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Intentionally empty. This case doesn't make sense because there's no 4360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * such thing as a premature disconnect when the disconnect itself 4370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * indicates the end of the data stream. 4380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 4390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 4420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 4430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 4440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(truncateViolently(response, 16)); 4450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 4460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson BufferedReader reader = new BufferedReader(new InputStreamReader( 4490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.getUrl("/").openConnection().getInputStream())); 4500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", reader.readLine()); 4510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson reader.readLine(); 4530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("This implementation silently ignored a truncated HTTP body."); 4540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 4550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, cache.getSuccessCount()); 4590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 4600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Request #2", readAscii(connection)); 4610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getSuccessCount()); 4630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithContentLengthHeader() throws IOException { 4660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 4670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithChunkedEncoding() throws IOException { 4700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.CHUNKED); 4710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithNoLengthHeaders() throws IOException { 4740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 4750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 4780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 4790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 4800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 4810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 4820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 4850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = connection.getInputStream(); 4860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", readAscii(connection, 5)); 4870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 4880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.read(); 4900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Expected an IOException because the stream is closed."); 4910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 4920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, cache.getSuccessCount()); 4960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = server.getUrl("/").openConnection(); 49784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("Request #2", readAscii(connection)); 4980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getSuccessCount()); 5000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 502953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 50321dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 105 seconds ago 50421dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 5 seconds ago 50521dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (105 - 5) / 10 = 10 seconds 50621dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds from now 507953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 50821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 509953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 510953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 511953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 512953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 513953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URL url = server.getUrl("/"); 514953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 515953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 516953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 517953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertNull(connection.getHeaderField("Warning")); 51821dddca4064527116af7a1553de502c6d11138daJesse Wilson } 51921dddca4064527116af7a1553de502c6d11138daJesse Wilson 52021dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testDefaultExpirationDateConditionallyCached() throws Exception { 52121dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 115 seconds ago 52221dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 15 seconds ago 52321dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (115 - 15) / 10 = 10 seconds 52421dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds ago 52521dddca4064527116af7a1553de502c6d11138daJesse Wilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 5260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 52721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 52821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 5290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 533953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 534953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // last modified: 105 days ago 535953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // served: 5 days ago 536953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // default lifetime: (105 - 5) / 10 = 10 days 537953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // expires: 10 days from served date = 5 days from now 538953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 539953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 540953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 541953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 542953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 543953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 544953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 545953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 546953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 547953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 548953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 549953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 550953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 55121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testNoDefaultExpirationForUrlsWithQueryString() throws Exception { 55221dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 55321dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 55421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 55521dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 55621dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 55721dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 55821dddca4064527116af7a1553de502c6d11138daJesse Wilson 55921dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/?foo=bar"); 56021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(url.openConnection())); 56121dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 56221dddca4064527116af7a1553de502c6d11138daJesse Wilson } 56321dddca4064527116af7a1553de502c6d11138daJesse Wilson 5640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithLastModifiedHeader() throws Exception { 5650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 5660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 5670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 5680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 5690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithNoLastModifiedHeader() throws Exception { 5740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 5750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 5760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInTheFuture() throws Exception { 5790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 5800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 5810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgePreferredWithMaxAgeAndExpires() throws Exception { 5840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 5850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 5860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 5870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 5880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 5910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 5920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 5930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 5940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 5950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 5960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 60184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson /* 60284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * Chrome interprets max-age relative to the local clock. Both our cache 60384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * and Firefox both use the earlier of the local and server's clock. 60484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson */ 6050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 6060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 6070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithDateHeader() throws Exception { 6110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 6130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithNoDateHeader() throws Exception { 6170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 6180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 6190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 621adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeWithLastModifiedButNoServedDate() throws Exception { 622adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 623adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 624adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 625adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 626adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 627adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 628adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 629adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 630adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 631adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 632adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 633adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 63421dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverLowerSharedMaxAge() throws Exception { 63521dddca4064527116af7a1553de502c6d11138daJesse Wilson assertFullyCached(new MockResponse() 63621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 63721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60") 63821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=180")); 63921dddca4064527116af7a1553de502c6d11138daJesse Wilson } 64021dddca4064527116af7a1553de502c6d11138daJesse Wilson 64121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverHigherMaxAge() throws Exception { 64221dddca4064527116af7a1553de502c6d11138daJesse Wilson assertNotCached(new MockResponse() 64321dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 64421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=180") 64521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60")); 64621dddca4064527116af7a1553de502c6d11138daJesse Wilson } 64721dddca4064527116af7a1553de502c6d11138daJesse Wilson 6480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodOptionsIsNotCached() throws Exception { 6490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("OPTIONS", false); 6500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodGetIsCached() throws Exception { 6530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("GET", true); 6540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodHeadIsNotCached() throws Exception { 6570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("HEAD", false); 6590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPostIsNotCached() throws Exception { 6620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("POST", false); 6640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPutIsNotCached() throws Exception { 6670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("PUT", false); 6680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodDeleteIsNotCached() throws Exception { 6710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("DELETE", false); 6720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodTraceIsNotCached() throws Exception { 6750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("TRACE", false); 6760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 6790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 6800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache (potentially) 6810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. expect a cache hit or miss 6820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 6830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 6840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 6850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 1")); 6860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 6870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 2")); 6880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 6890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 6910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection request1 = (HttpURLConnection) url.openConnection(); 6930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson request1.setRequestMethod(requestMethod); 6940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, request1); 6950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 6960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 697953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection request2 = url.openConnection(); 6980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (expectCached) { 6990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 7000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } else { 7010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 7020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPostInvalidatesCache() throws Exception { 7060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("POST"); 7070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPutInvalidatesCache() throws Exception { 7100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("PUT"); 7110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testDeleteMethodInvalidatesCache() throws Exception { 7140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("DELETE"); 7150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testMethodInvalidates(String requestMethod) throws Exception { 7180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 7190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache 7200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. invalidate it 7210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 3. expect a cache miss 7220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 7240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 7250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 7260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("C")); 7270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 7320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection invalidate = (HttpURLConnection) url.openConnection(); 7340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setRequestMethod(requestMethod); 7350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, invalidate); 7360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(invalidate)); 7370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("C", readAscii(url.openConnection())); 7390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtag() throws Exception { 7420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1")); 7440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1")); 7450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInThePast() throws Exception { 7480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 7530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 7550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInTheFuture() throws Exception { 7590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 7600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 7620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 7630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCache() throws Exception { 7660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 7670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 7700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-cache")); 7750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCache() throws Exception { 7800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 7810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 7840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Pragma: no-cache")); 7890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStore() throws Exception { 7940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 7950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 7980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 7990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-store")); 8020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPartialRangeResponsesDoNotCorruptCache() throws Exception { 8050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 8060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. request a range 8070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. request a full document, expecting a cache miss 8080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 8090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("AA") 8100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 8110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 8120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Range: bytes 1000-1001/2000")); 8130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("BB")); 8140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 8170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection range = url.openConnection(); 8190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson range.addRequestProperty("Range", "bytes=1000-1001"); 8200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("AA", readAscii(range)); 8210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("BB", readAscii(url.openConnection())); 8230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerReturnsDocumentOlderThanCache() throws Exception { 8260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 8270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B") 8300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 8310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 8340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndConditionalCache() throws Exception { 8400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndFullCache() throws Exception { 8460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 8490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 8520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response 8530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(gzip("ABCABCABC".getBytes("UTF-8"))) 8540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Encoding: gzip")); 8550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 8560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpiresDateBeforeModifiedDate() throws Exception { 8630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertConditionallyCached(new MockResponse() 8640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 8650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 8660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 868adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMaxAge() throws IOException { 869adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 870adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 871adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 872adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 873adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 874adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 875adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 876adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 877adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 878adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 879adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "max-age=30"); 880adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 881adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 882adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 883adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMinFresh() throws IOException { 884adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 885adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60") 886adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 887adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 888adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 889adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 890adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 891adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 892adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 893adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 894adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 895adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 896adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 897c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestMaxStale() throws IOException { 898c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 899c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=120") 900c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 901c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("B")); 902c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 903c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 904c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 905c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 906c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 907c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 908c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(connection)); 909953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("110 HttpURLConnection \"Response is stale\"", 910953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 911c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 912c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 913c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithNoResponseCached() throws IOException { 914c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson // (no responses enqueued) 915c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 916c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 917953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 918c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 919c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 920c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 921c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 922c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithFullResponseCached() throws IOException { 923c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 924c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 925c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 926c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 927c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 928c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 929c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 930c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 931c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 932c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 933c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 934c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithConditionalResponseCached() throws IOException { 935c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 936c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 937c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 938c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 939c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 940c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 941953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 942c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 943c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 944c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 945c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 946c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 947c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A")); 948c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 949c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 950c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 951953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 952c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 953c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 954c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 955c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 95684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestCacheControlNoCache() throws Exception { 95784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 95884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 95984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 96084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 96184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 96284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 96384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 96484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 96584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 96684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 96784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 96884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Cache-Control", "no-cache"); 96984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 97084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 97184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 97284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestPragmaNoCache() throws Exception { 97384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 97484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 97584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 97684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 97784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 97884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 97984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 98084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 98184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 98284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 98384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 98484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Pragma", "no-cache"); 98584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 98684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 98784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 98884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 98984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 99084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("ETag: v3") 99184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 99284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 99384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 99484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-Modified-Since", ifModifiedSinceDate); 99584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 99684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate)); 99784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-None-Match: v3")); 99884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 99984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 100084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 100184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 100284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 100384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 100484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 100584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 100684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 100784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-None-Match", "v1"); 100884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 100984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 101084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate)); 101184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 101284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 101384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 101484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String conditionValue) throws Exception { 101584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(seed.setBody("A")); 101684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 101784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 101884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 101984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 102084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 102184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 102284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 102384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty(conditionName, conditionValue); 102484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 102584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 102684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 102784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.takeRequest(); // seed 102884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson return server.takeRequest(); 102984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 103084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 103184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedConditionWithoutCachedResult() throws Exception { 103284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 103384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 103484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 103584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 103684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 103784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 103884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 103984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 104084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 104184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 1042c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 104321dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationRequestHeaderPreventsCaching() throws Exception { 104421dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 104521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES)) 104621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60") 104721dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 104821dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 104921dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 105021dddca4064527116af7a1553de502c6d11138daJesse Wilson 105121dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/"); 1052953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 105321dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.addRequestProperty("Authorization", "password"); 105421dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(connection)); 105521dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 105621dddca4064527116af7a1553de502c6d11138daJesse Wilson } 105721dddca4064527116af7a1553de502c6d11138daJesse Wilson 105821dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithSMaxAge() throws Exception { 105921dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 106021dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60")); 106121dddca4064527116af7a1553de502c6d11138daJesse Wilson } 106221dddca4064527116af7a1553de502c6d11138daJesse Wilson 106321dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithPublic() throws Exception { 106421dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 106521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: public")); 106621dddca4064527116af7a1553de502c6d11138daJesse Wilson } 106721dddca4064527116af7a1553de502c6d11138daJesse Wilson 106821dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithMustRevalidate() throws Exception { 106921dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 107021dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: must-revalidate")); 107121dddca4064527116af7a1553de502c6d11138daJesse Wilson } 107221dddca4064527116af7a1553de502c6d11138daJesse Wilson 107321dddca4064527116af7a1553de502c6d11138daJesse Wilson public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception { 107421dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(response 107521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60") 107621dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 107721dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 107821dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 107921dddca4064527116af7a1553de502c6d11138daJesse Wilson 108021dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/"); 1081953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 108221dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.addRequestProperty("Authorization", "password"); 108321dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(connection)); 108421dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(url.openConnection())); 108521dddca4064527116af7a1553de502c6d11138daJesse Wilson } 108621dddca4064527116af7a1553de502c6d11138daJesse Wilson 108721dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testCacheControlMustRevalidate() throws Exception { 108821dddca4064527116af7a1553de502c6d11138daJesse Wilson fail("Cache-Control: must-revalidate"); // TODO 108921dddca4064527116af7a1553de502c6d11138daJesse Wilson } 109021dddca4064527116af7a1553de502c6d11138daJesse Wilson 1091953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testVaryResponsesAreNotSupported() throws Exception { 1092953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 1093953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Cache-Control: max-age=60") 1094953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Vary: Accept-Language") 1095953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 1096953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1097953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 1098953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1099953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URL url = server.getUrl("/"); 1100953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection1 = url.openConnection(); 1101953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 1102953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection1)); 1103953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1104953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection2 = url.openConnection(); 1105953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 1106953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("B", readAscii(connection2)); 1107953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1108953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1109953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testContentLocationDoesNotPopulateCache() throws Exception { 1110953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 1111953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Cache-Control: max-age=60") 1112953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Content-Location: /bar") 1113953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 1114953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1115953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 1116953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1117953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/foo").openConnection())); 1118953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("B", readAscii(server.getUrl("/bar").openConnection())); 1119953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1120953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 11210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 11220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @param delta the offset from the current date to use. Negative 11230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * values yield dates in the past; positive values yield dates in the 11240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * future. 11250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1126953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private String formatDate(long delta, TimeUnit timeUnit) { 1127953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson Date date = new Date(System.currentTimeMillis() + timeUnit.toMillis(delta)); 1128953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 1129953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson rfc1123.setTimeZone(TimeZone.getTimeZone("UTC")); 1130953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson return rfc1123.format(date); 11310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 11340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 11350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 11360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setDoOutput(true); 11370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream requestBody = invalidate.getOutputStream(); 11380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.write('x'); 11390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.close(); 11400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNotCached(MockResponse response) throws Exception { 11440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 11450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 11460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 11470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 11490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 11500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(url.openConnection())); 11510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 11540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @return the request with the conditional get headers. 11550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 11560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 11570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 1: condition succeeds 11580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 11590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 11600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 2: condition fails 11620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("B")); 11630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("C")); 11640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 11660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL valid = server.getUrl("/valid"); 11680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(valid.openConnection())); 11690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(valid.openConnection())); 11700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL invalid = server.getUrl("/invalid"); 11720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(invalid.openConnection())); 11730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("C", readAscii(invalid.openConnection())); 11740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.takeRequest(); // regular get 11760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return server.takeRequest(); // conditional get 11770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertFullyCached(MockResponse response) throws Exception { 11800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 11810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("B")); 11820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 11830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 11850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 11860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 11870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 11900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Shortens the body of {@code response} but not the corresponding headers. 11910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Only useful to test how clients respond to the premature conclusion of 11920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * the HTTP body. 11930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 11940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 11950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 11960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = new ArrayList<String>(response.getHeaders()); 11970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 11980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().clear(); 11990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().addAll(headers); 12000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 12010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 12040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Reads {@code count} characters from the stream. If the stream is 12050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * exhausted before {@code count} characters can be read, the remaining 12060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * characters are returned and the stream is closed. 12070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 12080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection, int count) throws IOException { 120984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 121084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 121184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson ? connection.getInputStream() 121284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson : httpConnection.getErrorStream(); 12130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson StringBuilder result = new StringBuilder(); 12140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 0; i < count; i++) { 12150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson int value = in.read(); 12160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (value == -1) { 12170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 12180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 12190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson result.append((char) value); 12210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return result.toString(); 12230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection) throws IOException { 12260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return readAscii(connection, Integer.MAX_VALUE); 12270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void reliableSkip(InputStream in, int length) throws IOException { 12300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson while (length > 0) { 12310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson length -= in.skip(length); 12320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1235953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private void assertBadGateway(HttpURLConnection connection) throws IOException { 1236c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson try { 1237c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.getInputStream(); 1238c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson fail(); 1239c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } catch (FileNotFoundException expected) { 1240c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1241953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(HttpURLConnection.HTTP_BAD_GATEWAY, connection.getResponseCode()); 1242953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(-1, connection.getErrorStream().read()); 1243c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1244c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 12450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson enum TransferKind { 12460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson CHUNKED() { 12470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) 12480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 12490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setChunkedBody(content, chunkSize); 12500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 12520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson FIXED_LENGTH() { 12530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 12540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 12550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 12570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson END_OF_STREAM() { 12580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 12590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 12600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 12610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 12620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (h.next().startsWith("Content-Length:")) { 12630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson h.remove(); 12640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 12650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 12690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson abstract void setBody(MockResponse response, byte[] content, int chunkSize) 12710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException; 12720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 12740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson setBody(response, content.getBytes("UTF-8"), chunkSize); 12750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 12790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 12800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 12830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Returns a gzipped copy of {@code bytes}. 12840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 12850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public byte[] gzip(byte[] bytes) throws IOException { 12860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 12870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 12880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.write(bytes); 12890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.close(); 12900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return bytesOut.toByteArray(); 12910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private static class InsecureResponseCache extends ResponseCache { 12940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private final HttpResponseCache delegate = new HttpResponseCache(); 12950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 12970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return delegate.put(uri, connection); 12980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 13010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 13020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final CacheResponse response = delegate.get(uri, requestMethod, requestHeaders); 13030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (response instanceof SecureCacheResponse) { 13040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return new CacheResponse() { 13050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public InputStream getBody() throws IOException { 13060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getBody(); 13070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public Map<String, List<String>> getHeaders() throws IOException { 13090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getHeaders(); 13100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 13120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 13140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson} 1317