HttpResponseCacheTest.java revision 953df613522e12a418cb7cb73248594d6c9f53d4
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 3210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCachingAndRedirects() throws IOException { 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 3440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSecureResponseCachingAndRedirects() throws IOException { 3450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 3460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 3470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 3510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /foo")); 3520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 3530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 3540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 3550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC")); 3560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 3570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 3600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached! 3640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", readAscii(connection)); 3660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(2, cache.getMissCount()); // 1 redirect + 1 final response = 2 3680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(2, cache.getHitCount()); 3690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseCacheRequestHeaders() throws IOException, URISyntaxException { 3720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 3730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final AtomicReference<Map<String, List<String>>> requestHeadersRef 3760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson = new AtomicReference<Map<String, List<String>>>(); 3770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(new ResponseCache() { 3780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 3790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 3800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestHeadersRef.set(requestHeaders); 3810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 3820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 3840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return null; 3850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }); 3870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 3890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection urlConnection = url.openConnection(); 3900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("A", "android"); 3910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(urlConnection); 3920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("android"), requestHeadersRef.get().get("A")); 3930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 3970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 3980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 4010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerPrematureDisconnect(TransferKind.CHUNKED); 4020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 4050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 4060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Intentionally empty. This case doesn't make sense because there's no 4070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * such thing as a premature disconnect when the disconnect itself 4080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * indicates the end of the data stream. 4090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 4100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 4130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 4140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 4150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(truncateViolently(response, 16)); 4160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 4170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson BufferedReader reader = new BufferedReader(new InputStreamReader( 4200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.getUrl("/").openConnection().getInputStream())); 4210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", reader.readLine()); 4220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson reader.readLine(); 4240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("This implementation silently ignored a truncated HTTP body."); 4250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 4260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, cache.getSuccessCount()); 4300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 4310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Request #2", readAscii(connection)); 4320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getSuccessCount()); 4340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithContentLengthHeader() throws IOException { 4370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 4380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithChunkedEncoding() throws IOException { 4410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.CHUNKED); 4420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientPrematureDisconnectWithNoLengthHeaders() throws IOException { 4450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 4460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 4490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 4500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 4510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 4520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 4530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 4560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = connection.getInputStream(); 4570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", readAscii(connection, 5)); 4580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 4590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.read(); 4610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Expected an IOException because the stream is closed."); 4620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 4630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, cache.getSuccessCount()); 4670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = server.getUrl("/").openConnection(); 46884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("Request #2", readAscii(connection)); 4690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getAbortCount()); 4700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, cache.getSuccessCount()); 4710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 473953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 47421dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 105 seconds ago 47521dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 5 seconds ago 47621dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (105 - 5) / 10 = 10 seconds 47721dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds from now 478953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 47921dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 480953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 481953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 482953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 483953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 484953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URL url = server.getUrl("/"); 485953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 486953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 487953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 488953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertNull(connection.getHeaderField("Warning")); 48921dddca4064527116af7a1553de502c6d11138daJesse Wilson } 49021dddca4064527116af7a1553de502c6d11138daJesse Wilson 49121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testDefaultExpirationDateConditionallyCached() throws Exception { 49221dddca4064527116af7a1553de502c6d11138daJesse Wilson // last modified: 115 seconds ago 49321dddca4064527116af7a1553de502c6d11138daJesse Wilson // served: 15 seconds ago 49421dddca4064527116af7a1553de502c6d11138daJesse Wilson // default lifetime: (115 - 15) / 10 = 10 seconds 49521dddca4064527116af7a1553de502c6d11138daJesse Wilson // expires: 10 seconds from served date = 5 seconds ago 49621dddca4064527116af7a1553de502c6d11138daJesse Wilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 4970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 49821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 49921dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 5000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 504953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testDefaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 505953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // last modified: 105 days ago 506953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // served: 5 days ago 507953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // default lifetime: (105 - 5) / 10 = 10 days 508953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // expires: 10 days from served date = 5 days from now 509953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 510953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 511953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 512953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 513953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 514953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 515953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 516953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 517953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection)); 518953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 519953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 520953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 521953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 52221dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testNoDefaultExpirationForUrlsWithQueryString() throws Exception { 52321dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 52421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 52521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 52621dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 52721dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 52821dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 52921dddca4064527116af7a1553de502c6d11138daJesse Wilson 53021dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/?foo=bar"); 53121dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(url.openConnection())); 53221dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 53321dddca4064527116af7a1553de502c6d11138daJesse Wilson } 53421dddca4064527116af7a1553de502c6d11138daJesse Wilson 5350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithLastModifiedHeader() throws Exception { 5360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 5370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 5380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 5390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 5400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInThePastWithNoLastModifiedHeader() throws Exception { 5450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 5460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 5470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpirationDateInTheFuture() throws Exception { 5500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 5510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 5520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgePreferredWithMaxAgeAndExpires() throws Exception { 5550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 5560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 5570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 5580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 5590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 5620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 5630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 5640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 5650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 5660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 5670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 5680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 5690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 57284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson /* 57384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * Chrome interprets max-age relative to the local clock. Both our cache 57484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * and Firefox both use the earlier of the local and server's clock. 57584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson */ 5760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 5770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 5780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 5790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithDateHeader() throws Exception { 5820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 5830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 5840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 5850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMaxAgeInTheFutureWithNoDateHeader() throws Exception { 5880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 5890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: max-age=60")); 5900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 592adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeWithLastModifiedButNoServedDate() throws Exception { 593adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 594adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 595adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 596adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 597adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 598adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testMaxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 599adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertFullyCached(new MockResponse() 600adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 601adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 602adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60")); 603adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 604adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 60521dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverLowerSharedMaxAge() throws Exception { 60621dddca4064527116af7a1553de502c6d11138daJesse Wilson assertFullyCached(new MockResponse() 60721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 60821dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60") 60921dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=180")); 61021dddca4064527116af7a1553de502c6d11138daJesse Wilson } 61121dddca4064527116af7a1553de502c6d11138daJesse Wilson 61221dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testMaxAgePreferredOverHigherMaxAge() throws Exception { 61321dddca4064527116af7a1553de502c6d11138daJesse Wilson assertNotCached(new MockResponse() 61421dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 61521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=180") 61621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60")); 61721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 61821dddca4064527116af7a1553de502c6d11138daJesse Wilson 6190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodOptionsIsNotCached() throws Exception { 6200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("OPTIONS", false); 6210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodGetIsCached() throws Exception { 6240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("GET", true); 6250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodHeadIsNotCached() throws Exception { 6280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("HEAD", false); 6300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPostIsNotCached() throws Exception { 6330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // We could support this but choose not to for implementation simplicity 6340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("POST", false); 6350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodPutIsNotCached() throws Exception { 6380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("PUT", false); 6390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodDeleteIsNotCached() throws Exception { 6420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("DELETE", false); 6430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestMethodTraceIsNotCached() throws Exception { 6460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testRequestMethod("TRACE", false); 6470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 6500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 6510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache (potentially) 6520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. expect a cache hit or miss 6530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 6540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 6550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 6560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 1")); 6570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 6580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("X-Response-ID: 2")); 6590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 6600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 6620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection request1 = (HttpURLConnection) url.openConnection(); 6640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson request1.setRequestMethod(requestMethod); 6650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, request1); 6660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 6670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 668953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection request2 = url.openConnection(); 6690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (expectCached) { 6700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 6710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } else { 6720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 6730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPostInvalidatesCache() throws Exception { 6770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("POST"); 6780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPutInvalidatesCache() throws Exception { 6810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("PUT"); 6820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testDeleteMethodInvalidatesCache() throws Exception { 6850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMethodInvalidates("DELETE"); 6860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testMethodInvalidates(String requestMethod) throws Exception { 6890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 6900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. seed the cache 6910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. invalidate it 6920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 3. expect a cache miss 6930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 6940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 6950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 6960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 6970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("C")); 6980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 6990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 7030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection invalidate = (HttpURLConnection) url.openConnection(); 7050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setRequestMethod(requestMethod); 7060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson addRequestBodyIfNecessary(requestMethod, invalidate); 7070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(invalidate)); 7080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("C", readAscii(url.openConnection())); 7100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtag() throws Exception { 7130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1")); 7150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1")); 7160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInThePast() throws Exception { 7190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 7240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 7260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testEtagAndExpirationDateInTheFuture() throws Exception { 7300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFullyCached(new MockResponse() 7310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("ETag: v1") 7320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 7330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 7340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCache() throws Exception { 7370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 7380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 7410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-cache")); 7460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCache() throws Exception { 7510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 7520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 7550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 7560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse() 7570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 7580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Pragma: no-cache")); 7600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = conditionalRequest.getHeaders(); 7610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 7620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStore() throws Exception { 7650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 7660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testCacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 7690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNotCached(new MockResponse() 7700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 7710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Cache-Control: no-store")); 7730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testPartialRangeResponsesDoNotCorruptCache() throws Exception { 7760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 7770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 1. request a range 7780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 2. request a full document, expecting a cache miss 7790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("AA") 7810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 7820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 7830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Range: bytes 1000-1001/2000")); 7840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("BB")); 7850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection range = url.openConnection(); 7900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson range.addRequestProperty("Range", "bytes=1000-1001"); 7910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("AA", readAscii(range)); 7920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("BB", readAscii(url.openConnection())); 7940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerReturnsDocumentOlderThanCache() throws Exception { 7970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A") 7980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 7990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B") 8010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 8020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 8050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 8080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndConditionalCache() throws Exception { 8110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 8140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonIdentityEncodingAndFullCache() throws Exception { 8170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNonIdentityEncodingCached(new MockResponse() 8180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 8190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 8200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 8230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response 8240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(gzip("ABCABCABC".getBytes("UTF-8"))) 8250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Encoding: gzip")); 8260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 8270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(server.getUrl("/").openConnection())); 8310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testExpiresDateBeforeModifiedDate() throws Exception { 8340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertConditionallyCached(new MockResponse() 8350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 8360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 8370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 839adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMaxAge() throws IOException { 840adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 841adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 842adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 843adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 844adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 845adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 846adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 847adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 848adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 849adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 850adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "max-age=30"); 851adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 852adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 853adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 854adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testRequestMinFresh() throws IOException { 855adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("A") 856adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Cache-Control: max-age=60") 857adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 858adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 859adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 860adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 861adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 862adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 863adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 864adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 865adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("B", readAscii(connection)); 866adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 867adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 868c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestMaxStale() throws IOException { 869c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 870c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=120") 871c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 872c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("B")); 873c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 874c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 875c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 876c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 877c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 878c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 879c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(connection)); 880953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("110 HttpURLConnection \"Response is stale\"", 881953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.getHeaderField("Warning")); 882c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 883c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 884c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithNoResponseCached() throws IOException { 885c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson // (no responses enqueued) 886c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 887c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 888953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 889c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 890c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 891c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 892c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 893c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithFullResponseCached() throws IOException { 894c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 895c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 896c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 897c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 898c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 899c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 900c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 901c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 902c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 903c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 904c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 905c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithConditionalResponseCached() throws IOException { 906c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A") 907c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Cache-Control: max-age=30") 908c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 909c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 910c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 911c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 912953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 913c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 914c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 915c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 916c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 917c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testRequestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 918c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.enqueue(new MockResponse().setBody("A")); 919c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 920c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 921c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("A", readAscii(server.getUrl("/").openConnection())); 922953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 923c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 924c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertBadGateway(connection); 925c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 926c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 92784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestCacheControlNoCache() throws Exception { 92884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 92984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 93084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 93184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 93284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 93384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 93484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 93584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 93684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 93784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 93884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 93984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Cache-Control", "no-cache"); 94084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 94184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 94284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 94384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testRequestPragmaNoCache() throws Exception { 94484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 94584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 94684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 94784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=60") 94884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setBody("A")); 94984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 95084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 95184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 95284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 95384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 95484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URLConnection connection = url.openConnection(); 95584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestProperty("Pragma", "no-cache"); 95684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("B", readAscii(connection)); 95784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 95884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 95984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 96084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 96184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("ETag: v3") 96284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 96384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 96484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 96584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-Modified-Since", ifModifiedSinceDate); 96684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 96784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate)); 96884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-None-Match: v3")); 96984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 97084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 97184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 97284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 97384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson MockResponse response = new MockResponse() 97484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Last-Modified: " + lastModifiedDate) 97584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 97684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .addHeader("Cache-Control: max-age=0"); 97784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson RecordedRequest request = assertClientSuppliedCondition( 97884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson response, "If-None-Match", "v1"); 97984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson List<String> headers = request.getHeaders(); 98084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertTrue(headers.contains("If-None-Match: v1")); 98184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate)); 98284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 98384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 98484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 98584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String conditionValue) throws Exception { 98684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(seed.setBody("A")); 98784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 98884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 98984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 99084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson URL url = server.getUrl("/"); 99184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 99284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 99384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 99484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty(conditionName, conditionValue); 99584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 99684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 99784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 99884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.takeRequest(); // seed 99984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson return server.takeRequest(); 100084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 100184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 100284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testClientSuppliedConditionWithoutCachedResult() throws Exception { 100384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse() 100484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 100584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 100684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 100784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 100884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 100984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 101084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 101184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("", readAscii(connection)); 101284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 1013c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 101421dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationRequestHeaderPreventsCaching() throws Exception { 101521dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 101621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES)) 101721dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: max-age=60") 101821dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("A")); 101921dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("B")); 102021dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 102121dddca4064527116af7a1553de502c6d11138daJesse Wilson 102221dddca4064527116af7a1553de502c6d11138daJesse Wilson URL url = server.getUrl("/"); 1023953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection = url.openConnection(); 102421dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.addRequestProperty("Authorization", "password"); 102521dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("A", readAscii(connection)); 102621dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("B", readAscii(url.openConnection())); 102721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 102821dddca4064527116af7a1553de502c6d11138daJesse Wilson 102921dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithSMaxAge() throws Exception { 103021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 103121dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: s-maxage=60")); 103221dddca4064527116af7a1553de502c6d11138daJesse Wilson } 103321dddca4064527116af7a1553de502c6d11138daJesse Wilson 103421dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithPublic() throws Exception { 103521dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 103621dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: public")); 103721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 103821dddca4064527116af7a1553de502c6d11138daJesse Wilson 103921dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthorizationResponseCachedWithMustRevalidate() throws Exception { 104021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertAuthorizationRequestFullyCached(new MockResponse() 104121dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Cache-Control: must-revalidate")); 104221dddca4064527116af7a1553de502c6d11138daJesse Wilson } 104321dddca4064527116af7a1553de502c6d11138daJesse Wilson 104421dddca4064527116af7a1553de502c6d11138daJesse Wilson public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception { 104521dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(response 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("A", readAscii(url.openConnection())); 105621dddca4064527116af7a1553de502c6d11138daJesse Wilson } 105721dddca4064527116af7a1553de502c6d11138daJesse Wilson 105821dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testCacheControlMustRevalidate() throws Exception { 105921dddca4064527116af7a1553de502c6d11138daJesse Wilson fail("Cache-Control: must-revalidate"); // TODO 106021dddca4064527116af7a1553de502c6d11138daJesse Wilson } 106121dddca4064527116af7a1553de502c6d11138daJesse Wilson 1062953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testVaryResponsesAreNotSupported() throws Exception { 1063953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 1064953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Cache-Control: max-age=60") 1065953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Vary: Accept-Language") 1066953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 1067953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1068953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 1069953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1070953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URL url = server.getUrl("/"); 1071953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection1 = url.openConnection(); 1072953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 1073953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection1)); 1074953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1075953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection connection2 = url.openConnection(); 1076953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 1077953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("B", readAscii(connection2)); 1078953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1079953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1080953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testContentLocationDoesNotPopulateCache() throws Exception { 1081953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse() 1082953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Cache-Control: max-age=60") 1083953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Content-Location: /bar") 1084953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("A")); 1085953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 1086953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 1087953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1088953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(server.getUrl("/foo").openConnection())); 1089953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("B", readAscii(server.getUrl("/bar").openConnection())); 1090953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1091953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 10920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 10930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @param delta the offset from the current date to use. Negative 10940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * values yield dates in the past; positive values yield dates in the 10950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * future. 10960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 1097953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private String formatDate(long delta, TimeUnit timeUnit) { 1098953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson Date date = new Date(System.currentTimeMillis() + timeUnit.toMillis(delta)); 1099953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 1100953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson rfc1123.setTimeZone(TimeZone.getTimeZone("UTC")); 1101953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson return rfc1123.format(date); 11020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 11050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 11060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 11070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson invalidate.setDoOutput(true); 11080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream requestBody = invalidate.getOutputStream(); 11090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.write('x'); 11100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestBody.close(); 11110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertNotCached(MockResponse response) throws Exception { 11150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 11160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("B")); 11170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 11180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 11200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 11210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(url.openConnection())); 11220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 11250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * @return the request with the conditional get headers. 11260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 11270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 11280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 1: condition succeeds 11290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 11300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 11310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // scenario 2: condition fails 11330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("B")); 11340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("C")); 11350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 11370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL valid = server.getUrl("/valid"); 11390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(valid.openConnection())); 11400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(valid.openConnection())); 11410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL invalid = server.getUrl("/invalid"); 11430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", readAscii(invalid.openConnection())); 11440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("C", readAscii(invalid.openConnection())); 11450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.takeRequest(); // regular get 11470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return server.takeRequest(); // conditional get 11480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void assertFullyCached(MockResponse response) throws Exception { 11510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("A")); 11520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response.setBody("B")); 11530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 11540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 11560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 11570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", readAscii(url.openConnection())); 11580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 11610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Shortens the body of {@code response} but not the corresponding headers. 11620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Only useful to test how clients respond to the premature conclusion of 11630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * the HTTP body. 11640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 11650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 11660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 11670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson List<String> headers = new ArrayList<String>(response.getHeaders()); 11680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 11690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().clear(); 11700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.getHeaders().addAll(headers); 11710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 11720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 11750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Reads {@code count} characters from the stream. If the stream is 11760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * exhausted before {@code count} characters can be read, the remaining 11770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * characters are returned and the stream is closed. 11780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 11790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection, int count) throws IOException { 118084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 118184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 118284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson ? connection.getInputStream() 118384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson : httpConnection.getErrorStream(); 11840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson StringBuilder result = new StringBuilder(); 11850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 0; i < count; i++) { 11860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson int value = in.read(); 11870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (value == -1) { 11880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 11890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 11900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson result.append((char) value); 11920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return result.toString(); 11940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 11960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(URLConnection connection) throws IOException { 11970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return readAscii(connection, Integer.MAX_VALUE); 11980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 11990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void reliableSkip(InputStream in, int length) throws IOException { 12010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson while (length > 0) { 12020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson length -= in.skip(length); 12030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1206953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private void assertBadGateway(HttpURLConnection connection) throws IOException { 1207c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson try { 1208c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.getInputStream(); 1209c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson fail(); 1210c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } catch (FileNotFoundException expected) { 1211c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1212953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(HttpURLConnection.HTTP_BAD_GATEWAY, connection.getResponseCode()); 1213953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(-1, connection.getErrorStream().read()); 1214c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 1215c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 12160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson enum TransferKind { 12170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson CHUNKED() { 12180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) 12190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException { 12200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setChunkedBody(content, chunkSize); 12210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 12230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson FIXED_LENGTH() { 12240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 12250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 12260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }, 12280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson END_OF_STREAM() { 12290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 12300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setBody(content); 12310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson response.setSocketPolicy(DISCONNECT_AT_END); 12320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 12330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (h.next().startsWith("Content-Length:")) { 12340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson h.remove(); 12350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 12360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 12400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson abstract void setBody(MockResponse response, byte[] content, int chunkSize) 12420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException; 12430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 12450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson setBody(response, content.getBytes("UTF-8"), chunkSize); 12460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 12500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 12510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 12540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Returns a gzipped copy of {@code bytes}. 12550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 12560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public byte[] gzip(byte[] bytes) throws IOException { 12570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 12580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 12590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.write(bytes); 12600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson gzippedOut.close(); 12610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return bytesOut.toByteArray(); 12620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private static class InsecureResponseCache extends ResponseCache { 12650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private final HttpResponseCache delegate = new HttpResponseCache(); 12660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 12680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return delegate.put(uri, connection); 12690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public CacheResponse get(URI uri, String requestMethod, 12720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders) throws IOException { 12730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson final CacheResponse response = delegate.get(uri, requestMethod, requestHeaders); 12740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (response instanceof SecureCacheResponse) { 12750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return new CacheResponse() { 12760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public InputStream getBody() throws IOException { 12770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getBody(); 12780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override public Map<String, List<String>> getHeaders() throws IOException { 12800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response.getHeaders(); 12810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson }; 12830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return response; 12850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson} 1288