17899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath/* 27899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Copyright (C) 2011 The Android Open Source Project 37899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 47899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License"); 57899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * you may not use this file except in compliance with the License. 67899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * You may obtain a copy of the License at 77899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 87899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * http://www.apache.org/licenses/LICENSE-2.0 97899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * 107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Unless required by applicable law or agreed to in writing, software 117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS, 127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * See the License for the specific language governing permissions and 147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * limitations under the License. 157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */ 167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 17e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpackage com.squareup.okhttp; 18e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 19e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.internal.Internal; 202231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.SslContextBuilder; 21166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.internal.Util; 2271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport com.squareup.okhttp.internal.io.InMemoryFileSystem; 23166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.MockResponse; 24166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.MockWebServer; 25166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.RecordedRequest; 267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.BufferedReader; 277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.File; 287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.FileNotFoundException; 297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.IOException; 307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStream; 317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStreamReader; 327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.OutputStream; 337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieHandler; 347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieManager; 357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpCookie; 367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpURLConnection; 377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.ResponseCache; 387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URL; 397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URLConnection; 402231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.Principal; 412231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.cert.Certificate; 427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.DateFormat; 437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.SimpleDateFormat; 447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.ArrayList; 457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Arrays; 467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Date; 477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.List; 487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Locale; 497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.TimeZone; 507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.TimeUnit; 5171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport javax.net.ssl.HostnameVerifier; 5271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport javax.net.ssl.HttpsURLConnection; 5371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport javax.net.ssl.SSLContext; 5471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport javax.net.ssl.SSLSession; 5571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport okio.Buffer; 5671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport okio.BufferedSink; 5771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport okio.GzipSink; 5871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport okio.Okio; 5971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport org.junit.After; 6071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport org.junit.Before; 6171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport org.junit.Rule; 6271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport org.junit.Test; 6354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 64166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport static com.squareup.okhttp.mockwebserver.SocketPolicy.DISCONNECT_AT_END; 652231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertEquals; 662231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertFalse; 672231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertNotNull; 682231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertNull; 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertSame; 702231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertTrue; 712231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.fail; 727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 73e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller/** Test caching with {@link OkUrlFactory}. */ 74e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpublic final class UrlConnectionCacheTest { 7554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final HostnameVerifier NULL_HOSTNAME_VERIFIER = new HostnameVerifier() { 7654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public boolean verify(String s, SSLSession sslSession) { 7754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return true; 7854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 7954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 8171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller @Rule public MockWebServer server = new MockWebServer(); 8271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller @Rule public MockWebServer server2 = new MockWebServer(); 836c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer @Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem(); 84e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 8571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller private final SSLContext sslContext = SslContextBuilder.localhost(); 86e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private final OkUrlFactory client = new OkUrlFactory(new OkHttpClient()); 87e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private Cache cache; 8854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final CookieManager cookieManager = new CookieManager(); 8954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 9054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Before public void setUp() throws Exception { 91e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.setProtocolNegotiationEnabled(false); 9271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem); 93e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.client().setCache(cache); 9454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(cookieManager); 9554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 9654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 9754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @After public void tearDown() throws Exception { 9854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(null); 9954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(null); 1006c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer cache.delete(); 10154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 10254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void responseCacheAccessWithOkHttpMember() throws IOException { 104e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSame(cache, client.client().getCache()); 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 10754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 10854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Test that response caching is consistent with the RI and the spec. 10954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 11054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 11154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingByResponseCode() throws Exception { 112e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Test each documented HTTP/1.1 code, plus the first unused value in each range. 113e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 114e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 115e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // We can't test 100 because it's not really a response. 116e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // assertCached(false, 100); 117e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 101); 118e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 102); 119e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 200); 120e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 201); 121e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 202); 122e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 203); 123e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 204); 124e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 205); 125e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 206); //Electing to not cache partial responses 126e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 207); 127e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 300); 128e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 301); 129e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 302); 130e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 303); 131e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 304); 132e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 305); 133e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 306); 134e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 307); 135e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 308); 136e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 400); 137e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 401); 138e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 402); 139e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 403); 140e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 404); 141e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 405); 142e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 406); 143e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 408); 144e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 409); 145e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // the HTTP spec permits caching 410s, but the RI doesn't. 146e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 410); 147e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 411); 148e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 412); 149e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 413); 150e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 414); 151e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 415); 152e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 416); 153e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 417); 154e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 418); 155e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 156e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 500); 157e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(true, 501); 158e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 502); 159e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 503); 160e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 504); 161e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 505); 162e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertCached(false, 506); 16354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertCached(boolean shouldPut, int responseCode) throws Exception { 16654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server = new MockWebServer(); 167e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller MockResponse response = new MockResponse() 168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 170e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setResponseCode(responseCode) 171e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody("ABCDE") 172e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("WWW-Authenticate: challenge"); 17354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) { 17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("Proxy-Authenticate: Basic realm=\"protected area\""); 17554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { 17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("WWW-Authenticate: Basic realm=\"protected area\""); 17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 17854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 179e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.start(); 18054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 182e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection conn = client.open(url); 18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(responseCode, conn.getResponseCode()); 18454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 18554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // exhaust the content stream 18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(conn); 18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Response cached = cache.get(new Request.Builder().url(url).build()); 18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (shouldPut) { 19054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotNull(Integer.toString(responseCode), cached); 1913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller cached.body().close(); 19254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 19354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(Integer.toString(responseCode), cached); 19454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 19554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 19754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithFixedLength() throws IOException { 19954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.FIXED_LENGTH); 20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 20154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 20354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.CHUNKED); 20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 20554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 20654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 20754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.END_OF_STREAM); 20854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 20954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 21154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 21254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://code.google.com/p/android/issues/detail?id=8175 21354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testResponseCaching(TransferKind transferKind) throws IOException { 21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setStatus("HTTP/1.1 200 Fantastic"); 21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Make sure that calling skip() doesn't omit bytes from the cache. 223e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection urlConnection = client.open(server.getUrl("/")); 22454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = urlConnection.getInputStream(); 22554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love ", readAscii(urlConnection, "I love ".length())); 22654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reliableSkip(in, "puppies but hate ".length()); 22754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("spiders", readAscii(urlConnection, "spiders".length())); 22854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 23254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 233e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller urlConnection = client.open(server.getUrl("/")); // cached! 23454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in = urlConnection.getInputStream(); 23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love puppies but hate spiders", 23654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(urlConnection, "I love puppies but hate spiders".length())); 23754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(200, urlConnection.getResponseCode()); 23854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 23954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 24054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 24154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 24254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 24354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 24454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 24554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 24654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 24754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 24854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCaching() throws IOException { 24954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 25054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 25154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 25254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 25354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 2543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller HttpsURLConnection c1 = (HttpsURLConnection) client.open(server.getUrl("/")); 2553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c1.setSSLSocketFactory(sslContext.getSocketFactory()); 2563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 2573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("ABC", readAscii(c1)); 25854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 2603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String suite = c1.getCipherSuite(); 2613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Certificate> localCerts = toListOrNull(c1.getLocalCertificates()); 2623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Certificate> serverCerts = toListOrNull(c1.getServerCertificates()); 2633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Principal peerPrincipal = c1.getPeerPrincipal(); 2643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Principal localPrincipal = c1.getLocalPrincipal(); 2653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 2663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller HttpsURLConnection c2 = (HttpsURLConnection) client.open(server.getUrl("/")); // cached! 2673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c2.setSSLSocketFactory(sslContext.getSocketFactory()); 2683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller c2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 2693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("ABC", readAscii(c2)); 27054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 27154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 27254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 27354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 27454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 2753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(suite, c2.getCipherSuite()); 2763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(localCerts, toListOrNull(c2.getLocalCertificates())); 2773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(serverCerts, toListOrNull(c2.getServerCertificates())); 2783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(peerPrincipal, c2.getPeerPrincipal()); 2793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(localPrincipal, c2.getLocalPrincipal()); 28054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 28154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 28254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndRedirects() throws Exception { 28354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 28454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 28554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 28654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 28754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 28854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 28954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 29054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 29154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 292e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 295e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller connection = client.open(server.getUrl("/")); // cached! 29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 29854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects 29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getNetworkCount()); 30054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 30254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void redirectToCachedResult() throws Exception { 30454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("ABC")); 30554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 30654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 30854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 309e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", readAscii(client.open(server.getUrl("/foo")))); 31054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request1 = server.takeRequest(); 31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /foo HTTP/1.1", request1.getRequestLine()); 31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, request1.getSequenceNumber()); 31354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 314e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", readAscii(client.open(server.getUrl("/bar")))); 31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request2 = server.takeRequest(); 31654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /bar HTTP/1.1", request2.getRequestLine()); 31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, request2.getSequenceNumber()); 31854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 31954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // an unrelated request should reuse the pooled connection 320e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("DEF", readAscii(client.open(server.getUrl("/baz")))); 32154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request3 = server.takeRequest(); 32254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /baz HTTP/1.1", request3.getRequestLine()); 32354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, request3.getSequenceNumber()); 32454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 32554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 32654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCachingAndRedirects() throws IOException { 32754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 32854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 32954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 33054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 33154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 33254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 33354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 33454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 33554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 33654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 337e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.client().setSslSocketFactory(sslContext.getSocketFactory()); 338e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.client().setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 339166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 34054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(server.getUrl("/")); 34154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection1)); 3423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNotNull(connection1.getCipherSuite()); 34354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 34454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Cached! 34554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(server.getUrl("/")); 34654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection2)); 3473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNotNull(connection2.getCipherSuite()); 34854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 34954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 35054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 3513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(connection1.getCipherSuite(), connection2.getCipherSuite()); 35274623587bf099735cf16ec2298005f12fd3fcb07jwilson } 35374623587bf099735cf16ec2298005f12fd3fcb07jwilson 35474623587bf099735cf16ec2298005f12fd3fcb07jwilson /** 35574623587bf099735cf16ec2298005f12fd3fcb07jwilson * We've had bugs where caching and cross-protocol redirects yield class 35674623587bf099735cf16ec2298005f12fd3fcb07jwilson * cast exceptions internal to the cache because we incorrectly assumed that 35774623587bf099735cf16ec2298005f12fd3fcb07jwilson * HttpsURLConnection was always HTTPS and HttpURLConnection was always HTTP; 35874623587bf099735cf16ec2298005f12fd3fcb07jwilson * in practice redirects mean that each can do either. 35974623587bf099735cf16ec2298005f12fd3fcb07jwilson * 36074623587bf099735cf16ec2298005f12fd3fcb07jwilson * https://github.com/square/okhttp/issues/214 36174623587bf099735cf16ec2298005f12fd3fcb07jwilson */ 36274623587bf099735cf16ec2298005f12fd3fcb07jwilson @Test public void secureResponseCachingAndProtocolRedirects() throws IOException { 36374623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.useHttps(sslContext.getSocketFactory(), false); 36474623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 36574623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 36674623587bf099735cf16ec2298005f12fd3fcb07jwilson .setBody("ABC")); 36774623587bf099735cf16ec2298005f12fd3fcb07jwilson server2.enqueue(new MockResponse().setBody("DEF")); 36874623587bf099735cf16ec2298005f12fd3fcb07jwilson 36974623587bf099735cf16ec2298005f12fd3fcb07jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 37074623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 37174623587bf099735cf16ec2298005f12fd3fcb07jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 37274623587bf099735cf16ec2298005f12fd3fcb07jwilson .addHeader("Location: " + server2.getUrl("/"))); 37374623587bf099735cf16ec2298005f12fd3fcb07jwilson 374e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.client().setSslSocketFactory(sslContext.getSocketFactory()); 375e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.client().setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 37674623587bf099735cf16ec2298005f12fd3fcb07jwilson 37774623587bf099735cf16ec2298005f12fd3fcb07jwilson HttpURLConnection connection1 = client.open(server.getUrl("/")); 37874623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals("ABC", readAscii(connection1)); 37974623587bf099735cf16ec2298005f12fd3fcb07jwilson 38074623587bf099735cf16ec2298005f12fd3fcb07jwilson // Cached! 38174623587bf099735cf16ec2298005f12fd3fcb07jwilson HttpURLConnection connection2 = client.open(server.getUrl("/")); 38274623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals("ABC", readAscii(connection2)); 38374623587bf099735cf16ec2298005f12fd3fcb07jwilson 38474623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 38574623587bf099735cf16ec2298005f12fd3fcb07jwilson assertEquals(2, cache.getHitCount()); 38654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 38754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 38854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 38954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 39054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 39154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 39354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.CHUNKED); 39454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 39554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 39754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Intentionally empty. This case doesn't make sense because there's no 39854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // such thing as a premature disconnect when the disconnect itself 39954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // indicates the end of the data stream. 40054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 40154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 40254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 40354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse(); 40454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 40554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(truncateViolently(response, 16)); 40654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 40754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 40854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson BufferedReader reader = new BufferedReader( 409e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller new InputStreamReader(client.open(server.getUrl("/")).getInputStream())); 41054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", reader.readLine()); 41154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 41254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.readLine(); 41354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("This implementation silently ignored a truncated HTTP body."); 41454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 41554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 41654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.close(); 41754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 41854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 41954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 42054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 421e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 42254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 42354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 42454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 42554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 42654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 42754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithContentLengthHeader() throws IOException { 42854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 42954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 43054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 43154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithChunkedEncoding() throws IOException { 43254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.CHUNKED); 43354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 43454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 43554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithNoLengthHeaders() throws IOException { 43654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 43754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 43854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 43954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 44054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Setting a low transfer speed ensures that stream discarding will time out. 4413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller MockResponse response = new MockResponse().throttleBody(6, 1, TimeUnit.SECONDS); 44254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 44354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 44454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 44554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 446e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 44754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = connection.getInputStream(); 44854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", readAscii(connection, 5)); 44954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 45054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 45154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.read(); 45254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("Expected an IOException because the stream is closed."); 45354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 45454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 45554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 45654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 45754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 458e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller connection = client.open(server.getUrl("/")); 45954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 46054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 46154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 46254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 46354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 46454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 46554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 seconds ago 46654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 seconds ago 46754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 seconds 46854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds from now 46954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 47054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 47154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 47254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 47354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 47454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 475e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 476e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(url); 47754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 47854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(connection.getHeaderField("Warning")); 47954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 48054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 48154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateConditionallyCached() throws Exception { 48254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 115 seconds ago 48354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 15 seconds ago 48454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (115 - 15) / 10 = 10 seconds 48554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds ago 48654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 48754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 48854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 48954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 490e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 49154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 49254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 49354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 49454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 days ago 49554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 days ago 49654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 days 49754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 days from served date = 5 days from now 49854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 49954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 50054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 50154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 502e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 503e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 50454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 50554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 50654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 50754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 50854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 50954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void noDefaultExpirationForUrlsWithQueryString() throws Exception { 51054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 51154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 51254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 51354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 51454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 51554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 51654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/?foo=bar"); 517e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 518e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(url))); 51954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 52054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithLastModifiedHeader() throws Exception { 52254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 52354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 52454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 52554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 526e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 52754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 52854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithNoLastModifiedHeader() throws Exception { 53054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 53154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 53254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 53354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInTheFuture() throws Exception { 53454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 53554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 53654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 53754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredWithMaxAgeAndExpires() throws Exception { 53854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 53954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 54054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 54154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 54254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 54354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 54454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 54554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 54654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 54754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 54854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 549e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 55054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 55154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 55254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 55354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Chrome interprets max-age relative to the local clock. Both our cache 55454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // and Firefox both use the earlier of the local and server's clock. 55554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 55654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 55754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 55854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 55954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateHeader() throws Exception { 56054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 56154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 56254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 56354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 56454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithNoDateHeader() throws Exception { 56554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Cache-Control: max-age=60")); 56654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 56754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 56854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeWithLastModifiedButNoServedDate() throws Exception { 56954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 57054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 57154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 57254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 57354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 57454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 57554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 57654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 57754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 57854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 57954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 58054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 58154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverLowerSharedMaxAge() throws Exception { 58254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 58354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=60") 58454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=180")); 58554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 58654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 58754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverHigherMaxAge() throws Exception { 58854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 58954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=180") 59054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 59154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 59254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 59354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodOptionsIsNotCached() throws Exception { 59454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("OPTIONS", false); 59554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 59654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 59754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodGetIsCached() throws Exception { 59854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("GET", true); 59954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 60054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 60154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodHeadIsNotCached() throws Exception { 60254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 60354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("HEAD", false); 60454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 60554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 60654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPostIsNotCached() throws Exception { 60754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 60854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("POST", false); 60954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 61054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 61154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPutIsNotCached() throws Exception { 61254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("PUT", false); 61354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 61454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 61554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodDeleteIsNotCached() throws Exception { 61654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("DELETE", false); 61754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 61854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 61954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodTraceIsNotCached() throws Exception { 62054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("TRACE", false); 62154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 62254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 62354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 62454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache (potentially) 62554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. expect a cache hit or miss 62654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 62754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("X-Response-ID: 1")); 62854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("X-Response-ID: 2")); 62954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 63054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 63154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 632e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection request1 = client.open(url); 63354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson request1.setRequestMethod(requestMethod); 63454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, request1); 635e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller request1.getInputStream().close(); 63654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 63754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 638e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection request2 = client.open(url); 639e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller request2.getInputStream().close(); 64054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (expectCached) { 6413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("1", request2.getHeaderField("X-Response-ID")); 64254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 64354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 64454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 64554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 64654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 64754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void postInvalidatesCache() throws Exception { 64854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("POST"); 64954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 65054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 65154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void putInvalidatesCache() throws Exception { 65254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("PUT"); 65354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 65454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 65554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void deleteMethodInvalidatesCache() throws Exception { 65654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("DELETE"); 65754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 65854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 65954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testMethodInvalidates(String requestMethod) throws Exception { 66054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache 66154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. invalidate it 66254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 3. expect a cache miss 66354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 66454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().setBody("A").addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 66554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 66654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 66754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 66854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 66954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 670e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 67154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 672e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection invalidate = client.open(url); 67354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setRequestMethod(requestMethod); 67454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, invalidate); 67554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(invalidate)); 67654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 677e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("C", readAscii(client.open(url))); 67854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 67954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 680a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath @Test public void postInvalidatesCacheWithUncacheableResponse() throws Exception { 681a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 1. seed the cache 682a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 2. invalidate it with uncacheable response 683a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath // 3. expect a cache miss 684a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue( 685a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath new MockResponse().setBody("A").addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 686a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue(new MockResponse().setBody("B").setResponseCode(500)); 687a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath server.enqueue(new MockResponse().setBody("C")); 688a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 689a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath URL url = server.getUrl("/"); 690a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 691e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 692a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 693e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection invalidate = client.open(url); 694a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath invalidate.setRequestMethod("POST"); 695a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath addRequestBodyIfNecessary("POST", invalidate); 696a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath assertEquals("B", readAscii(invalidate)); 697a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 698e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("C", readAscii(client.open(url))); 699a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath } 700a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath 70154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etag() throws Exception { 70254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = 70354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached(new MockResponse().addHeader("ETag: v1")); 704e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("v1", conditionalRequest.getHeader("If-None-Match")); 70554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 70654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 70754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInThePast() throws Exception { 70854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 70954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 71054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v1") 71154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 71254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 713e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("v1", conditionalRequest.getHeader("If-None-Match")); 7143be78b8b0ca13d9e05e2327acb8d8654f719a3f6Neil Fuller assertNull(conditionalRequest.getHeader("If-Modified-Since")); 71554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 71654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 71754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInTheFuture() throws Exception { 71854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("ETag: v1") 71954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 72054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 72154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 72254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCache() throws Exception { 72454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 72554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 72654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 72854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 72954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 73054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 73154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 73254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-cache")); 733e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 73454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 73554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 73654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCache() throws Exception { 73754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 73854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 73954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 74154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 74254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 74354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 74454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 74554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Pragma: no-cache")); 746e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(lastModifiedDate, conditionalRequest.getHeader("If-Modified-Since")); 74754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStore() throws Exception { 75054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 75154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 75254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 75454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 75554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 75654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-store")); 75754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 75854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void partialRangeResponsesDoNotCorruptCache() throws Exception { 76054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. request a range 76154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. request a full document, expecting a cache miss 76254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("AA") 76354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 76454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 76554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Range: bytes 1000-1001/2000")); 76654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("BB")); 76754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 76954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 770e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection range = client.open(url); 77154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson range.addRequestProperty("Range", "bytes=1000-1001"); 77254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("AA", readAscii(range)); 77354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 774e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("BB", readAscii(client.open(url))); 77554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 77654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 77754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverReturnsDocumentOlderThanCache() throws Exception { 77854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 77954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 78054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 78154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B") 78254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 78354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 78454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 78554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 786e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 787e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 78854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 78954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 79054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndConditionalCache() throws Exception { 79154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 79254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 79354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 79454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 79554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 79654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndFullCache() throws Exception { 79754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 79854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 79954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 80054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 80154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 80254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 80354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 804e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setBody(gzip("ABCABCABC")).addHeader("Content-Encoding: gzip")); 80554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 806166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 80754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 808166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath // At least three request/response pairs are required because after the first request is cached 809166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath // a different execution path might be taken. Thus modifications to the cache applied during 810166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath // the second request might not be visible until another request is performed. 811e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCABCABC", readAscii(client.open(server.getUrl("/")))); 812e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCABCABC", readAscii(client.open(server.getUrl("/")))); 813e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCABCABC", readAscii(client.open(server.getUrl("/")))); 81454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 81554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 816166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath @Test public void notModifiedSpecifiesEncoding() throws Exception { 817166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 818e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody(gzip("ABCABCABC")) 819166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Content-Encoding: gzip") 820166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 821166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 822166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 823166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED) 824166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .addHeader("Content-Encoding: gzip")); 825166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 826166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .setBody("DEFDEFDEF")); 827166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 828e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCABCABC", readAscii(client.open(server.getUrl("/")))); 829e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCABCABC", readAscii(client.open(server.getUrl("/")))); 830e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("DEFDEFDEF", readAscii(client.open(server.getUrl("/")))); 831e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 832e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 833e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** https://github.com/square/okhttp/issues/947 */ 834e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void gzipAndVaryOnAcceptEncoding() throws Exception { 835e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse() 836e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .setBody(gzip("ABCABCABC")) 837e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Encoding: gzip") 838e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Vary: Accept-Encoding") 839e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 840e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse().setBody("FAIL")); 841e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 842e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCABCABC", readAscii(client.open(server.getUrl("/")))); 843e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABCABCABC", readAscii(client.open(server.getUrl("/")))); 844166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath } 845166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 846c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller @Test public void conditionalCacheHitIsNotDoublePooled() throws Exception { 847c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller server.enqueue(new MockResponse().addHeader("ETag: v1").setBody("A")); 848c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller server.enqueue(new MockResponse() 849c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller .clearHeaders() 850c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 851c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 852c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller ConnectionPool pool = ConnectionPool.getDefault(); 853c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller pool.evictAll(); 854e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.client().setConnectionPool(pool); 855c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 856e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 857e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 8586c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer assertEquals(1, client.client().getConnectionPool().getIdleConnectionCount()); 859c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller } 860c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller 86154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expiresDateBeforeModifiedDate() throws Exception { 86254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached( 86354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 86454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 86554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 86654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 86754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxAge() throws IOException { 86854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 86954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 87054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 87154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 87254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 87354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 874e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 87554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 876e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 87754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-age=30"); 87854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 87954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 88054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 88154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMinFresh() throws IOException { 88254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 88354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 88454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 88554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 88654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 887e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 88854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 889e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 89054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 89154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 89254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 89354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 89454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStale() throws IOException { 89554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 89654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120") 89754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 89854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 89954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 900e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 90154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 902e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 90354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 90454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 90554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("110 HttpURLConnection \"Response is stale\"", 90654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 90754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 90854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 90954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStaleNotHonoredWithMustRevalidate() throws IOException { 91054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 91154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120, must-revalidate") 91254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 91354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 91454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 915e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 91654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 917e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 91854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 91954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 92054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 92154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 92254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithNoResponseCached() throws IOException { 92354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (no responses enqueued) 92454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 925e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 92654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 92754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 9283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getRequestCount()); 9293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getNetworkCount()); 9303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getHitCount()); 93154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 93254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 93354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithFullResponseCached() throws IOException { 93454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 93554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 93654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 93754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 938e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 939e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 94054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 941faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 9423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(2, cache.getRequestCount()); 9433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getNetworkCount()); 9443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getHitCount()); 94554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 94654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 94754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithConditionalResponseCached() throws IOException { 94854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 94954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 95054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 95154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 952e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 953e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 95454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 95554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 9563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(2, cache.getRequestCount()); 9573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getNetworkCount()); 9583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getHitCount()); 95954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 96054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 96154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 96254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 96354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 964e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 965e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 96654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 96754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 9683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(2, cache.getRequestCount()); 9693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(1, cache.getNetworkCount()); 9703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(0, cache.getHitCount()); 97154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 97254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 97354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestCacheControlNoCache() throws Exception { 97454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 97554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 97654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 97754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 97854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 97954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 98054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 98154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 982e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 983e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(url); 98454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Cache-Control", "no-cache"); 98554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 98654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 98754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 98854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestPragmaNoCache() throws Exception { 98954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 99054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 99154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 99254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 99354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 99454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 99554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 99654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 997e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 998e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(url); 99954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Pragma", "no-cache"); 100054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 100154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 100254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 100354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 100454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 100554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v3").addHeader("Cache-Control: max-age=0"); 100654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 100754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = 100854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertClientSuppliedCondition(response, "If-Modified-Since", ifModifiedSinceDate); 1009e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(ifModifiedSinceDate, request.getHeader("If-Modified-Since")); 1010e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(request.getHeader("If-None-Match")); 101154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 101254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 101354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 101454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 101554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 101654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 101754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0"); 101854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = assertClientSuppliedCondition(response, "If-None-Match", "v1"); 1019e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("v1", request.getHeader("If-None-Match")); 1020e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(request.getHeader("If-Modified-Since")); 102154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 102254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 102354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 102454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String conditionValue) throws Exception { 102554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(seed.setBody("A")); 102654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 102754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 102854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1029e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 103054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1031e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(url); 103254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty(conditionName, conditionValue); 103354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 103454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 103554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 103654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // seed 103754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); 103854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 103954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 10403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 10413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Confirm that {@link URLConnection#setIfModifiedSince} causes an 10423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * If-Modified-Since header with a GMT timestamp. 10433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 10443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * https://code.google.com/p/android/issues/detail?id=66135 10453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 104654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void setIfModifiedSince() throws Exception { 104754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 104854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 104954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1050e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(url); 10513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller connection.setIfModifiedSince(1393666200000L); 105254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 105354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = server.takeRequest(); 10543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String ifModifiedSinceHeader = request.getHeader("If-Modified-Since"); 10553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals("Sat, 01 Mar 2014 09:30:00 GMT", ifModifiedSinceHeader); 10563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 10573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 10583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 10593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * For Last-Modified and Date headers, we should echo the date back in the 10603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * exact format we were served. 10613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 10623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Test public void retainServedDateFormat() throws Exception { 10633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // Serve a response with a non-standard date format that OkHttp supports. 10643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Date lastModifiedDate = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(-1)); 10653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Date servedDate = new Date(System.currentTimeMillis() + TimeUnit.HOURS.toMillis(-2)); 10663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller DateFormat dateFormat = new SimpleDateFormat("EEE dd-MMM-yyyy HH:mm:ss z", Locale.US); 10673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller dateFormat.setTimeZone(TimeZone.getTimeZone("EDT")); 10683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String lastModifiedString = dateFormat.format(lastModifiedDate); 10693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String servedString = dateFormat.format(servedDate); 10703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 10713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // This response should be conditionally cached. 10723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.enqueue(new MockResponse() 10733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .addHeader("Last-Modified: " + lastModifiedString) 10743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .addHeader("Expires: " + servedString) 10753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .setBody("A")); 10763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller server.enqueue(new MockResponse() 10773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 10783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1079e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1080e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 10813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 10823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // The first request has no conditions. 10833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller RecordedRequest request1 = server.takeRequest(); 10843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertNull(request1.getHeader("If-Modified-Since")); 10853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 10863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // The 2nd request uses the server's date format. 10873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller RecordedRequest request2 = server.takeRequest(); 10883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller assertEquals(lastModifiedString, request2.getHeader("If-Modified-Since")); 108954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 109054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 109154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedConditionWithoutCachedResult() throws Exception { 109254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 109354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1094e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 109554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 109654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 109754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 109854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 109954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 110054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void authorizationRequestFullyCached() throws Exception { 1102e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A")); 110354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 110454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 110554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1106e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(url); 110754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Authorization", "password"); 110854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 1109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 111054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 111154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 111254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void contentLocationDoesNotPopulateCache() throws Exception { 111354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 111454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Location: /bar") 111554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 111654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 111754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1118e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/foo")))); 1119e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(server.getUrl("/bar")))); 112054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 112154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 112254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotWriteToCache() throws Exception { 112354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 112454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 112554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 112654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1127e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 112854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 112954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 1130e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(server.getUrl("/")))); 113154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 113254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 113354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotReadFromCache() throws Exception { 113454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 113554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 113654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 113754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1138e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1139e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 114054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 114154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 114254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 114354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 114454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultUseCachesSetsInitialValueOnly() throws Exception { 114554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = new URL("http://localhost/"); 1146e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection c1 = client.open(url); 1147e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection c2 = client.open(url); 114854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getDefaultUseCaches()); 114954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(false); 115054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 115154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getUseCaches()); 115254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c2.getUseCaches()); 1153e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection c3 = client.open(url); 115454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(c3.getUseCaches()); 115554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 115654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(true); 115754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 115854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 115954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 116054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void connectionIsReturnedToPoolAfterConditionalSuccess() throws Exception { 116154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 116254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 116354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 116454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 116554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 116654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1167e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/a")))); 1168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/a")))); 1169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(server.getUrl("/b")))); 117054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 117154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, server.takeRequest().getSequenceNumber()); 117254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, server.takeRequest().getSequenceNumber()); 117354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.takeRequest().getSequenceNumber()); 117454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 117554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 117654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheMiss() throws Exception { 117754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 117854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 117954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 118054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 118154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 118254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1183e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 118454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 118554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 118654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 1187e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(server.getUrl("/")))); 1188e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("C", readAscii(client.open(server.getUrl("/")))); 118954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 119054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 119154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 119254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 119354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 119454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheHit() throws Exception { 119554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 119654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 119754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 119854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 119954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 120054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1201e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 120254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 120354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 120454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 1205e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1206e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 120754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 120854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 120954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 121054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 121154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 121254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsFullCacheHit() throws Exception { 121354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A")); 121454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1215e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 121654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 121754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 121854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 1219e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1220e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 122154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 122254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 122354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 122454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 122554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 122654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesChangedRequestHeaderField() throws Exception { 122754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 122854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 122954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 123054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 123154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 123254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1233e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection frConnection = client.open(url); 123454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 123554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 123654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection enConnection = client.open(url); 123854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-US"); 123954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 124054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 124154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 124254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesUnchangedRequestHeaderField() throws Exception { 124354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 124454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 124554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 124654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 124754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 124854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1249e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(url); 125054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 125154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 1252e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(url); 125354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 125454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 125554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 125654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 125754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAbsentRequestHeaderField() throws Exception { 125854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 125954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 126054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 126154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 126254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1263e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 126554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 126654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 126754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAddedRequestHeaderField() throws Exception { 126854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 126954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 127054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 127154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 127254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1273e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1274e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection fooConnection = client.open(server.getUrl("/")); 127554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 127654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(fooConnection)); 127754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 127854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 127954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesRemovedRequestHeaderField() throws Exception { 128054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 128154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 128254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 128354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 128454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1285e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection fooConnection = client.open(server.getUrl("/")); 128654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 128754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(fooConnection)); 1288e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(server.getUrl("/")))); 128954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 129054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 129154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyFieldsAreCaseInsensitive() throws Exception { 129254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 129354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: ACCEPT-LANGUAGE") 129454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 129554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 129654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 129754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1298e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(url); 129954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 130054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 1301e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(url); 130254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("accept-language", "fr-CA"); 130354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 130454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 130554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 130654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithMatch() throws Exception { 130754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 130854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 130954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 131054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 131154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 131254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 131354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1314e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(url); 131554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 131654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Charset", "UTF-8"); 131754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Encoding", "identity"); 131854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 1319e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(url); 132054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 132154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Charset", "UTF-8"); 132254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Encoding", "identity"); 132354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 132454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 132554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 132654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithNoMatch() throws Exception { 132754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 132854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 132954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 133054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 133154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 133254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 133354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1334e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection frConnection = client.open(url); 133554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 133654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Charset", "UTF-8"); 133754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Encoding", "identity"); 133854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 1339e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection enConnection = client.open(url); 134054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-CA"); 134154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Charset", "UTF-8"); 134254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Encoding", "identity"); 134354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 134454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 134554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 134654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithMatch() throws Exception { 134754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 134854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 134954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 135054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 135154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 135254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1353e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(url); 135454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 135554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 135654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 135754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1358e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(url); 135954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 136054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 136154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 136254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 136354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 136454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithNoMatch() throws Exception { 136554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 136654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 136754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 136854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 136954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 137054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1371e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(url); 137254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 137354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 137454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 137554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1376e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(url); 137754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 137854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 137954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection2)); 138054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 138154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 138254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAsterisk() throws Exception { 138354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 138454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: *") 138554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 138654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 138754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1388e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1389e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(server.getUrl("/")))); 139054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 139154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 139254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAndHttps() throws Exception { 139354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 139454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 139554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 139654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 139754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 139854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 139954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 140054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(url); 140154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 140254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 140354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 140454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 140554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 140654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(url); 140754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setSSLSocketFactory(sslContext.getSocketFactory()); 140854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 140954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 141054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 141154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 141254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 141354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusCookies() throws Exception { 141454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 141554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";") 141654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 141754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 141854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 141954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 142054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";") 142154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 142254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 142354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1424e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 142554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=FIRST"); 1426e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 142754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=SECOND"); 142854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 142954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 143054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsNetworkEndToEndHeaders() throws Exception { 143154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD") 143254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 143354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 143454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 143554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD, PUT") 143654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 143754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1438e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(server.getUrl("/")); 143954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 144054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection1.getHeaderField("Allow")); 144154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1442e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(server.getUrl("/")); 144354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 144454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD, PUT", connection2.getHeaderField("Allow")); 144554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 144654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 144754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsCachedHopByHopHeaders() throws Exception { 144854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: identity") 144954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 145054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 145154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 145254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: none") 145354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 145454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1455e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(server.getUrl("/")); 145654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 145754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection1.getHeaderField("Transfer-Encoding")); 145854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1459e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(server.getUrl("/")); 146054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 146154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection2.getHeaderField("Transfer-Encoding")); 146254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 146354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 146454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersDeletesCached100LevelWarnings() throws Exception { 146554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 199 test danger") 146654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 146754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 146854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 146954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 147054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1471e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(server.getUrl("/")); 147254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 147354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("199 test danger", connection1.getHeaderField("Warning")); 147454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1475e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(server.getUrl("/")); 147654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 147754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection2.getHeaderField("Warning")); 147854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 147954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 148054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersRetainsCached200LevelWarnings() throws Exception { 148154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 299 test danger") 148254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 148354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 148454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 148554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 148654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1487e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection1 = client.open(server.getUrl("/")); 148854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 148954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection1.getHeaderField("Warning")); 149054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1491e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection2 = client.open(server.getUrl("/")); 149254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 149354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection2.getHeaderField("Warning")); 149454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 149554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 149654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void assertCookies(URL url, String... expectedCookies) throws Exception { 1497e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller List<String> actualCookies = new ArrayList<>(); 149854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (HttpCookie cookie : cookieManager.getCookieStore().get(url.toURI())) { 149954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson actualCookies.add(cookie.toString()); 150054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 150154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList(expectedCookies), actualCookies); 150254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 150354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 150454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusRange() throws Exception { 150554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().setResponseCode(HttpURLConnection.HTTP_PARTIAL) 1506e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 1507e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Content-Range: bytes 100-100/200") 1508e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .addHeader("Cache-Control: max-age=60")); 150954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 151054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 151154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void conditionalHitUpdatesCache() throws Exception { 151254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS)) 151354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 151454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 151554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=30") 151654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Allow: GET, HEAD") 151754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 151854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 151954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 152054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // cache miss; seed the cache 1521e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection1 = client.open(server.getUrl("/a")); 152254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 152354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection1.getHeaderField("Allow")); 152454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 152554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // conditional cache hit; update the cache 1526e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection2 = client.open(server.getUrl("/a")); 152754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 152854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 152954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection2.getHeaderField("Allow")); 153054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 153154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // full cache hit 1532e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection3 = client.open(server.getUrl("/a")); 153354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection3)); 153454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection3.getHeaderField("Allow")); 153554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 153654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.getRequestCount()); 153754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 153854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1539faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderCached() throws IOException { 1540faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1541faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1542faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1543faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1544e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1545e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 1546faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath connection.addRequestProperty("Cache-Control", "only-if-cached"); 1547faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1548faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1549faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1550faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheFetched() throws IOException { 1551faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1552faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1553faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(-31, TimeUnit.MINUTES))); 1554faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("B") 1555faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1556faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1557faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1558e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1559e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 1560faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("B", readAscii(connection)); 1561faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1562faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1563faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheNotFetched() throws IOException { 1564faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1565faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=0") 1566faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1567faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setResponseCode(304)); 1568faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1569e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(server.getUrl("/")))); 1570e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection = client.open(server.getUrl("/")); 1571faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1572faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1573faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1574faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderFetched() throws IOException { 1575faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A")); 1576faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1577e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller URLConnection connection = client.open(server.getUrl("/")); 1578faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1579faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1580faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1581faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void emptyResponseHeaderNameFromCacheIsLenient() throws Exception { 1582e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Headers.Builder headers = new Headers.Builder() 1583e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller .add("Cache-Control: max-age=120"); 1584e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Internal.instance.addLenient(headers, ": A"); 1585e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller server.enqueue(new MockResponse().setHeaders(headers.build()).setBody("body")); 1586e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1587faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = client.open(server.getUrl("/")); 1588faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", connection.getHeaderField("")); 15896c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer assertEquals("body", readAscii(connection)); 1590faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1591faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 159254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 1593166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * Old implementations of OkHttp's response cache wrote header fields like 1594166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * ":status: 200 OK". This broke our cached response parser because it split 1595166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * on the first colon. This regression test exists to help us read these old 1596166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * bad cache entries. 1597166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * 1598166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath * https://github.com/square/okhttp/issues/227 1599166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath */ 1600166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath @Test public void testGoldenCacheResponse() throws Exception { 1601166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath cache.close(); 1602166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath server.enqueue(new MockResponse() 1603166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .clearHeaders() 1604166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1605166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 1606166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath URL url = server.getUrl("/"); 1607e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String urlKey = Util.md5Hex(url.toString()); 1608166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath String entryMetadata = "" 1609166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "" + url + "\n" 1610166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "GET\n" 1611166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "0\n" 1612166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "HTTP/1.1 200 OK\n" 1613166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "7\n" 1614166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + ":status: 200 OK\n" 1615166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + ":version: HTTP/1.1\n" 1616166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "etag: foo\n" 1617166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "content-length: 3\n" 1618166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "OkHttp-Received-Millis: " + System.currentTimeMillis() + "\n" 1619166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "X-Android-Response-Source: NETWORK 200\n" 1620166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "OkHttp-Sent-Millis: " + System.currentTimeMillis() + "\n" 1621166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "\n" 1622166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\n" 1623166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "1\n" 1624166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "MIIBpDCCAQ2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDEw1qd2lsc29uLmxvY2FsMB4XDTEzMDgy" 1625166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "OTA1MDE1OVoXDTEzMDgzMDA1MDE1OVowGDEWMBQGA1UEAxMNandpbHNvbi5sb2NhbDCBnzANBgkqhkiG9w0BAQEF" 1626166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "AAOBjQAwgYkCgYEAlFW+rGo/YikCcRghOyKkJanmVmJSce/p2/jH1QvNIFKizZdh8AKNwojt3ywRWaDULA/RlCUc" 1627166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "ltF3HGNsCyjQI/+Lf40x7JpxXF8oim1E6EtDoYtGWAseelawus3IQ13nmo6nWzfyCA55KhAWf4VipelEy8DjcuFK" 1628166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "v6L0xwXnI0ECAwEAATANBgkqhkiG9w0BAQsFAAOBgQAuluNyPo1HksU3+Mr/PyRQIQS4BI7pRXN8mcejXmqyscdP" 1629166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "7S6J21FBFeRR8/XNjVOp4HT9uSc2hrRtTEHEZCmpyoxixbnM706ikTmC7SN/GgM+SmcoJ1ipJcNcl8N0X6zym4dm" 1630166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "yFfXKHu2PkTo7QFdpOJFvP3lIigcSZXozfmEDg==\n" 1631166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "-1\n"; 1632166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath String entryBody = "abc"; 1633166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath String journalBody = "" 1634166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "libcore.io.DiskLruCache\n" 1635166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "1\n" 1636166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "201105\n" 1637166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "2\n" 1638166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "\n" 1639166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath + "CLEAN " + urlKey + " " + entryMetadata.length() + " " + entryBody.length() + "\n"; 1640166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath writeFile(cache.getDirectory(), urlKey + ".0", entryMetadata); 1641166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath writeFile(cache.getDirectory(), urlKey + ".1", entryBody); 1642166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath writeFile(cache.getDirectory(), "journal", journalBody); 164371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller cache = new Cache(cache.getDirectory(), Integer.MAX_VALUE, fileSystem); 1644e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller client.client().setCache(cache); 1645166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 1646166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath HttpURLConnection connection = client.open(url); 1647166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals(entryBody, readAscii(connection)); 1648166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("3", connection.getHeaderField("Content-Length")); 1649166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath assertEquals("foo", connection.getHeaderField("etag")); 1650166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath } 1651166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 1652166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath private void writeFile(File directory, String file, String content) throws IOException { 165371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller BufferedSink sink = Okio.buffer(fileSystem.sink(new File(directory, file))); 1654e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.writeUtf8(content); 1655e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.close(); 1656166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath } 1657166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath 1658166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath /** 165954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * @param delta the offset from the current date to use. Negative 166054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * values yield dates in the past; positive values yield dates in the 166154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * future. 166254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 166354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(long delta, TimeUnit timeUnit) { 166454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta))); 166554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 166654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 166754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(Date date) { 166854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 1669166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath rfc1123.setTimeZone(TimeZone.getTimeZone("GMT")); 167054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return rfc1123.format(date); 167154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 167254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 167354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 167454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 167554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 167654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setDoOutput(true); 167754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream requestBody = invalidate.getOutputStream(); 167854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.write('x'); 167954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.close(); 168054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 168154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 168254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 168354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNotCached(MockResponse response) throws Exception { 168454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 168554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 168654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 168754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1688e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 1689e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("B", readAscii(client.open(url))); 169054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 169154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 169254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** @return the request with the conditional get headers. */ 169354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception { 169454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // scenario 1: condition succeeds 169554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A").setStatus("HTTP/1.1 200 A-OK")); 169654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 169754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 169854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // scenario 2: condition fails 169954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("B").setStatus("HTTP/1.1 200 B-OK")); 170054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 C-OK").setBody("C")); 170154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 170254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL valid = server.getUrl("/valid"); 1703e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection1 = client.open(valid); 170454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 170554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection1.getResponseCode()); 170654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection1.getResponseMessage()); 1707e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection2 = client.open(valid); 170854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 170954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 171054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection2.getResponseMessage()); 171154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 171254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL invalid = server.getUrl("/invalid"); 1713e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection3 = client.open(invalid); 171454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection3)); 171554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection3.getResponseCode()); 171654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B-OK", connection3.getResponseMessage()); 1717e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller HttpURLConnection connection4 = client.open(invalid); 171854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(connection4)); 171954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection4.getResponseCode()); 172054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C-OK", connection4.getResponseMessage()); 172154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 172254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // regular get 172354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); // conditional get 172454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 172554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 172654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertFullyCached(MockResponse response) throws Exception { 172754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 172854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("B")); 172954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 173054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 1731e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 1732e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("A", readAscii(client.open(url))); 173354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 173454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 173554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 173654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Shortens the body of {@code response} but not the corresponding headers. 173754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Only useful to test how clients respond to the premature conclusion of 173854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * the HTTP body. 173954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 174054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 174154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setSocketPolicy(DISCONNECT_AT_END); 1742e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Headers headers = response.getHeaders(); 1743e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Buffer truncatedBody = new Buffer(); 1744e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller truncatedBody.write(response.getBody(), numBytesToKeep); 1745e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setBody(truncatedBody); 1746e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.setHeaders(headers); 174754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response; 174854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 174954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 175054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 175154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Reads {@code count} characters from the stream. If the stream is 175254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * exhausted before {@code count} characters can be read, the remaining 175354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * characters are returned and the stream is closed. 175454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 175554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection, int count) throws IOException { 175654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 175754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 17583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? connection.getInputStream() 17593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : httpConnection.getErrorStream(); 176054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson StringBuilder result = new StringBuilder(); 176154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 0; i < count; i++) { 176254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int value = in.read(); 176354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (value == -1) { 17647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath in.close(); 176554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 176654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 176754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson result.append((char) value); 176854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 176954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return result.toString(); 177054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 177154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 177254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection) throws IOException { 177354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return readAscii(connection, Integer.MAX_VALUE); 177454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 177554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 177654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void reliableSkip(InputStream in, int length) throws IOException { 177754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson while (length > 0) { 177854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson length -= in.skip(length); 177954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 178054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 178154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 178254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertGatewayTimeout(HttpURLConnection connection) throws IOException { 178354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 178454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getInputStream(); 178554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 178654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (FileNotFoundException expected) { 178754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 178854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(504, connection.getResponseCode()); 178954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, connection.getErrorStream().read()); 179054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 179154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 179254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enum TransferKind { 179354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CHUNKED() { 1794e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override void setBody(MockResponse response, Buffer content, int chunkSize) 179554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 179654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setChunkedBody(content, chunkSize); 179754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 179854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 179954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson FIXED_LENGTH() { 1800e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override void setBody(MockResponse response, Buffer content, int chunkSize) { 180154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 180254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 180354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 180454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson END_OF_STREAM() { 1805e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override void setBody(MockResponse response, Buffer content, int chunkSize) { 180654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 18077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath response.setSocketPolicy(DISCONNECT_AT_END); 1808e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller response.removeHeader("Content-Length"); 180954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 181054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 18117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 1812e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller abstract void setBody(MockResponse response, Buffer content, int chunkSize) throws IOException; 181354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 181454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 1815e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setBody(response, new Buffer().writeUtf8(content), chunkSize); 181654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 181754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 181854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 181954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 182054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 182154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 182254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 182354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns a gzipped copy of {@code bytes}. */ 1824e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller public Buffer gzip(String data) throws IOException { 1825e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Buffer result = new Buffer(); 1826e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSink sink = Okio.buffer(new GzipSink(result)); 1827e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.writeUtf8(data); 1828e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.close(); 1829e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return result; 183054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath} 1832