UrlConnectionCacheTest.java revision faf49723fb689c626f69876e718c58018eff8ee7
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 172231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpackage com.squareup.okhttp.internal.http; 187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.MockResponse; 207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.MockWebServer; 217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.RecordedRequest; 22faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport com.squareup.okhttp.HttpResponseCache; 232231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.OkHttpClient; 24faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport com.squareup.okhttp.ResponseSource; 252231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.SslContextBuilder; 267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.BufferedReader; 277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.ByteArrayOutputStream; 287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.File; 297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.FileNotFoundException; 307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.IOException; 317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStream; 327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStreamReader; 337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.OutputStream; 347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CacheRequest; 357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CacheResponse; 367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieHandler; 377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CookieManager; 387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpCookie; 397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.HttpURLConnection; 402231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.InetAddress; 417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.ResponseCache; 427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.SecureCacheResponse; 437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URI; 447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URISyntaxException; 457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URL; 467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URLConnection; 472231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.UnknownHostException; 482231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.GeneralSecurityException; 492231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.Principal; 502231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.security.cert.Certificate; 517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.DateFormat; 527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.SimpleDateFormat; 537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.ArrayList; 547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Arrays; 557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Collections; 567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Date; 577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Iterator; 587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.List; 597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Locale; 607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Map; 617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.TimeZone; 627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.UUID; 637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.TimeUnit; 647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.atomic.AtomicInteger; 657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.atomic.AtomicReference; 667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.zip.GZIPOutputStream; 672231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.HostnameVerifier; 682231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.HttpsURLConnection; 692231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.SSLContext; 702231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.SSLSession; 712231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport org.junit.After; 7254cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport org.junit.Before; 7354cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport org.junit.Test; 7454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 7554cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_END; 762231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertEquals; 772231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertFalse; 782231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertNotNull; 792231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertNull; 802231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertTrue; 812231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.fail; 827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 8354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson/** Android's HttpResponseCacheTest. */ 842231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpublic final class HttpResponseCacheTest { 8554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final HostnameVerifier NULL_HOSTNAME_VERIFIER = new HostnameVerifier() { 8654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public boolean verify(String s, SSLSession sslSession) { 8754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return true; 8854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 8954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 9054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final OkHttpClient client = new OkHttpClient(); 9154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private MockWebServer server = new MockWebServer(); 9254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private HttpResponseCache cache; 9354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private final CookieManager cookieManager = new CookieManager(); 9454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 9554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private static final SSLContext sslContext; 9654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson static { 9754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 9854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson sslContext = new SslContextBuilder(InetAddress.getLocalHost().getHostName()).build(); 9954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (GeneralSecurityException e) { 10054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 10154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (UnknownHostException e) { 10254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throw new RuntimeException(e); 10354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 10454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 10554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 10654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Before public void setUp() throws Exception { 10754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String tmp = System.getProperty("java.io.tmpdir"); 10854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID()); 10954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE); 11054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(cache); 11154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(cookieManager); 11254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 11354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 11454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @After public void tearDown() throws Exception { 11554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.shutdown(); 11654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(null); 117faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath cache.delete(); 11854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CookieHandler.setDefault(null); 11954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 12054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 12154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private HttpURLConnection openConnection(URL url) { 12254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return client.open(url); 12354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 12454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 12554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 12654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Test that response caching is consistent with the RI and the spec. 12754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 12854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 12954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingByResponseCode() throws Exception { 13054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Test each documented HTTP/1.1 code, plus the first unused value in each range. 13154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 13254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 13354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We can't test 100 because it's not really a response. 13454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // assertCached(false, 100); 13554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 101); 13654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 102); 13754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 200); 13854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 201); 13954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 202); 14054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 203); 14154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 204); 14254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 205); 14354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 206); // we don't cache partial responses 14454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 207); 14554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 300); 14654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 301); 14754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 302; i <= 308; ++i) { 14854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 14954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 15054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 400; i <= 406; ++i) { 15154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 15254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 15354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (See test_responseCaching_407.) 15454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 408); 15554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, 409); 15654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (See test_responseCaching_410.) 15754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 411; i <= 418; ++i) { 15854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 15954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 500; i <= 506; ++i) { 16154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(false, i); 16254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 16454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 16654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Response code 407 should only come from proxy servers. Android's client 16754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * throws if it is sent by an origin server. 16854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 16954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void originServerSends407() throws Exception { 17054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(407)); 17154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 17254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 17354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection conn = openConnection(url); 17554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson conn.getResponseCode(); 17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 17854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 17954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 18254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCaching_410() throws Exception { 18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // the HTTP spec permits caching 410s, but the RI doesn't. 18454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCached(true, 410); 18554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertCached(boolean shouldPut, int responseCode) throws Exception { 18854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server = new MockWebServer(); 18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 19054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 19154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 19254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(responseCode) 19354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABCDE") 19454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("WWW-Authenticate: challenge"); 19554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) { 19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("Proxy-Authenticate: Basic realm=\"protected area\""); 19754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { 19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.addHeader("WWW-Authenticate: Basic realm=\"protected area\""); 19954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 20154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 20354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection conn = openConnection(url); 20554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(responseCode, conn.getResponseCode()); 20654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 20754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // exhaust the content stream 20854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(conn); 20954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CacheResponse cached = 21154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cache.get(url.toURI(), "GET", Collections.<String, List<String>>emptyMap()); 21254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (shouldPut) { 21354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotNull(Integer.toString(responseCode), cached); 21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cached.getBody().close(); 21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(Integer.toString(responseCode), cached); 21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Test that we can interrogate the response when the cache is being 22354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * populated. http://code.google.com/p/android/issues/detail?id=7787 22454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 22554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCacheCallbackApis() throws Exception { 22654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final String body = "ABCDE"; 22754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final AtomicInteger cacheCount = new AtomicInteger(); 22854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().setStatus("HTTP/1.1 200 Fantastic").addHeader("fgh: ijk").setBody(body)); 23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 23254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 23354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(new ResponseCache() { 23454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheResponse get(URI uri, String requestMethod, 23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Map<String, List<String>> requestHeaders) throws IOException { 23654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 23754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 23854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 23954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection httpConnection = (HttpURLConnection) conn; 2402231db3e6bb54447a9b14cf004a6cb03c373651cjwilson try { 24154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.getRequestProperties(); 24254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 24354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalStateException expected) { 2447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 2457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath try { 24654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.addRequestProperty("K", "V"); 24754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 24854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IllegalStateException expected) { 2497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 25054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("HTTP/1.1 200 Fantastic", httpConnection.getHeaderField(null)); 25154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"), 25254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.getHeaderFields().get(null)); 25354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(200, httpConnection.getResponseCode()); 25454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Fantastic", httpConnection.getResponseMessage()); 25554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(body.length(), httpConnection.getContentLength()); 25654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ijk", httpConnection.getHeaderField("fgh")); 2577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath try { 25854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson httpConnection.getInputStream(); // the RI doesn't forbid this, but it should 25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 2607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } catch (IOException expected) { 2617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 26254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson cacheCount.incrementAndGet(); 26354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 26454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 26554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }); 26654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 26754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 26854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(url); 26954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(body, readAscii(connection)); 27054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cacheCount.get()); 27154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 27254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 27354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithFixedLength() throws IOException { 27454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.FIXED_LENGTH); 27554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 27654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 27754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 27854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.CHUNKED); 27954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 28054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 28154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 28254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testResponseCaching(TransferKind.END_OF_STREAM); 28354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 28454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 28554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 28654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 28754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * http://code.google.com/p/android/issues/detail?id=8175 28854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 28954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testResponseCaching(TransferKind transferKind) throws IOException { 29054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 29154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 29254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setStatus("HTTP/1.1 200 Fantastic"); 29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 29554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 29854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Make sure that calling skip() doesn't omit bytes from the cache. 29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection urlConnection = openConnection(server.getUrl("/")); 30054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = urlConnection.getInputStream(); 30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love ", readAscii(urlConnection, "I love ".length())); 30254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reliableSkip(in, "puppies but hate ".length()); 30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("spiders", readAscii(urlConnection, "spiders".length())); 30454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 30554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 30654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 30854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 30954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson urlConnection = openConnection(server.getUrl("/")); // cached! 31054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in = urlConnection.getInputStream(); 31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("I love puppies but hate spiders", 31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(urlConnection, "I love puppies but hate spiders".length())); 31354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(200, urlConnection.getResponseCode()); 31454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 31654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, in.read()); 31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 31854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 31954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteAbortCount()); 32054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 32154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 32254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 32354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 32454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCaching() throws IOException { 32554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 32654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 32754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 32854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 32954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 33054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 33154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection = (HttpsURLConnection) client.open(server.getUrl("/")); 33254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setSSLSocketFactory(sslContext.getSocketFactory()); 33354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 33454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 33554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 33654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // OpenJDK 6 fails on this line, complaining that the connection isn't open yet 33754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String suite = connection.getCipherSuite(); 33854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<Certificate> localCerts = toListOrNull(connection.getLocalCertificates()); 33954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<Certificate> serverCerts = toListOrNull(connection.getServerCertificates()); 34054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Principal peerPrincipal = connection.getPeerPrincipal(); 34154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Principal localPrincipal = connection.getLocalPrincipal(); 34254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 34354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = (HttpsURLConnection) client.open(server.getUrl("/")); // cached! 34454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setSSLSocketFactory(sslContext.getSocketFactory()); 34554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 34654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 34754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 34854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getRequestCount()); 34954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 35054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getHitCount()); 35154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 35254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(suite, connection.getCipherSuite()); 35354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(localCerts, toListOrNull(connection.getLocalCertificates())); 35454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(serverCerts, toListOrNull(connection.getServerCertificates())); 35554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(peerPrincipal, connection.getPeerPrincipal()); 35654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(localPrincipal, connection.getLocalPrincipal()); 35754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 35854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 35954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheReturnsInsecureResponseForSecureRequest() throws IOException { 36054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 36154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("ABC")); 36254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 36354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 36454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 36554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(new InsecureResponseCache()); 36654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 36754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(server.getUrl("/")); 36854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 36954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 37054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection1)); 37154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 37254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Not cached! 37354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(server.getUrl("/")); 37454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setSSLSocketFactory(sslContext.getSocketFactory()); 37554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 37654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("DEF", readAscii(connection2)); 37754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 37854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 37954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCachingAndRedirects() throws Exception { 38054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 38154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 38254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 38354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 38454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 38554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 38654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 38754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 38854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 38954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 39154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 39254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = openConnection(server.getUrl("/")); // cached! 39454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection)); 39554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 39654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects 39754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getNetworkCount()); 39854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 39954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 40054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 40154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void redirectToCachedResult() throws Exception { 40254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("ABC")); 40354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 40454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 40554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 40654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 40754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 40854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(openConnection(server.getUrl("/foo")))); 40954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request1 = server.takeRequest(); 41054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /foo HTTP/1.1", request1.getRequestLine()); 41154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, request1.getSequenceNumber()); 41254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 41354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(openConnection(server.getUrl("/bar")))); 41454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request2 = server.takeRequest(); 41554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /bar HTTP/1.1", request2.getRequestLine()); 41654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, request2.getSequenceNumber()); 41754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 41854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // an unrelated request should reuse the pooled connection 41954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("DEF", readAscii(openConnection(server.getUrl("/baz")))); 42054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request3 = server.takeRequest(); 42154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET /baz HTTP/1.1", request3.getRequestLine()); 42254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, request3.getSequenceNumber()); 42354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 42454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 42554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void secureResponseCachingAndRedirects() throws IOException { 42654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 42754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 42854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 42954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM) 43054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Location: /foo")); 43154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 43254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 43354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("ABC")); 43454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("DEF")); 43554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 43654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 43754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(server.getUrl("/")); 43854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 43954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 44054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection1)); 44154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 44254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Cached! 44354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(server.getUrl("/")); 44454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 44554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 44654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABC", readAscii(connection2)); 44754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 44854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4 44954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 45054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 45154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 45254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void responseCacheRequestHeaders() throws IOException, URISyntaxException { 45354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("ABC")); 45454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 45554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 45654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final AtomicReference<Map<String, List<String>>> requestHeadersRef = 45754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new AtomicReference<Map<String, List<String>>>(); 45854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ResponseCache.setDefault(new ResponseCache() { 45954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheResponse get(URI uri, String requestMethod, 46054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Map<String, List<String>> requestHeaders) throws IOException { 46154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestHeadersRef.set(requestHeaders); 46254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 46354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 46454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException { 46554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return null; 46654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 46754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }); 46854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 46954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 47054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection urlConnection = openConnection(url); 47154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson urlConnection.addRequestProperty("A", "android"); 47254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson readAscii(urlConnection); 47354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList("android"), requestHeadersRef.get().get("A")); 47454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 47554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 47654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 47754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 47854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 47954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 48054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 48154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testServerPrematureDisconnect(TransferKind.CHUNKED); 48254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 48354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 48454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 48554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Intentionally empty. This case doesn't make sense because there's no 48654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // such thing as a premature disconnect when the disconnect itself 48754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // indicates the end of the data stream. 48854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 48954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 49054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 49154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse(); 49254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 49354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(truncateViolently(response, 16)); 49454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 49554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 49654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 49754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson BufferedReader reader = new BufferedReader( 49854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new InputStreamReader(openConnection(server.getUrl("/")).getInputStream())); 49954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", reader.readLine()); 50054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 50154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.readLine(); 50254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("This implementation silently ignored a truncated HTTP body."); 50354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 50454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 50554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson reader.close(); 50654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 50754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 50854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 50954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 51054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 51154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 51254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 51354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 51454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 51554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 51654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithContentLengthHeader() throws IOException { 51754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 51854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 51954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithChunkedEncoding() throws IOException { 52154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.CHUNKED); 52254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 52354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientPrematureDisconnectWithNoLengthHeaders() throws IOException { 52554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 52654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 52754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 52854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 52954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Setting a low transfer speed ensures that stream discarding will time out. 53054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse().setBytesPerSecond(6); 53154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 53254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response); 53354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("Request #2")); 53454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 53554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 53654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 53754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = connection.getInputStream(); 53854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCDE", readAscii(connection, 5)); 53954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.close(); 54054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 54154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson in.read(); 54254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail("Expected an IOException because the stream is closed."); 54354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (IOException expected) { 54454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 54554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 54654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 54754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getWriteSuccessCount()); 54854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection = openConnection(server.getUrl("/")); 54954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("Request #2", readAscii(connection)); 55054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteAbortCount()); 55154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getWriteSuccessCount()); 55254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 55354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 55454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForLessThan24Hours() throws Exception { 55554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 seconds ago 55654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 seconds ago 55754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 seconds 55854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds from now 55954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 56054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 56154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 56254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 56354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 56454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 56554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 56654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 56754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 56854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 56954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNull(connection.getHeaderField("Warning")); 57054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 57154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 57254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateConditionallyCached() throws Exception { 57354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 115 seconds ago 57454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 15 seconds ago 57554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (115 - 15) / 10 = 10 seconds 57654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 seconds from served date = 5 seconds ago 57754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS); 57854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 57954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 58054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS))); 58154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 58254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 58354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 58454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 58554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception { 58654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // last modified: 105 days ago 58754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // served: 5 days ago 58854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // default lifetime: (105 - 5) / 10 = 10 days 58954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // expires: 10 days from served date = 5 days from now 59054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS)) 59154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS)) 59254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 59354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 59454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 59554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 59654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 59754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 59854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("113 HttpURLConnection \"Heuristic expiration\"", 59954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 60054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 60154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 60254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void noDefaultExpirationForUrlsWithQueryString() throws Exception { 60354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 60454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS)) 60554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS)) 60654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 60754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 60854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 60954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 61054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/?foo=bar"); 61154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 61254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 61354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 61454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 61554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithLastModifiedHeader() throws Exception { 61654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 61754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 61854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 61954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 62054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 62154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 62254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 62354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 62454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInThePastWithNoLastModifiedHeader() throws Exception { 62554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 62654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 62754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 62854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expirationDateInTheFuture() throws Exception { 62954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 63054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 63154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 63254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredWithMaxAgeAndExpires() throws Exception { 63354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 63454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)) 63554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 63654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 63754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 63854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception { 63954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 64054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 64154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 64254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 64354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 64454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 64554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 64654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 64754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 64854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception { 64954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // Chrome interprets max-age relative to the local clock. Both our cache 65054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // and Firefox both use the earlier of the local and server's clock. 65154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS)) 65254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 65354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 65454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 65554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateHeader() throws Exception { 65654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 65754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 65854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 65954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 66054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithNoDateHeader() throws Exception { 66154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Cache-Control: max-age=60")); 66254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 66354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 66454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeWithLastModifiedButNoServedDate() throws Exception { 66554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 66654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 66754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 66854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 66954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 67054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception { 67154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached( 67254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 67354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 67454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 67554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 67654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 67754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverLowerSharedMaxAge() throws Exception { 67854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 67954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=60") 68054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=180")); 68154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 68254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 68354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void maxAgePreferredOverHigherMaxAge() throws Exception { 68454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 68554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: s-maxage=180") 68654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 68754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 68854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 68954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodOptionsIsNotCached() throws Exception { 69054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("OPTIONS", false); 69154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 69254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 69354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodGetIsCached() throws Exception { 69454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("GET", true); 69554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 69654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 69754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodHeadIsNotCached() throws Exception { 69854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 69954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("HEAD", false); 70054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 70154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 70254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPostIsNotCached() throws Exception { 70354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // We could support this but choose not to for implementation simplicity 70454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("POST", false); 70554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 70654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 70754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodPutIsNotCached() throws Exception { 70854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("PUT", false); 70954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 71054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 71154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodDeleteIsNotCached() throws Exception { 71254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("DELETE", false); 71354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 71454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 71554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMethodTraceIsNotCached() throws Exception { 71654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testRequestMethod("TRACE", false); 71754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 71854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 71954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception { 72054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache (potentially) 72154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. expect a cache hit or miss 72254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 72354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("X-Response-ID: 1")); 72454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("X-Response-ID: 2")); 72554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 72654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 72854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 72954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection request1 = openConnection(url); 73054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson request1.setRequestMethod(requestMethod); 73154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, request1); 73254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 73354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 73454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection request2 = openConnection(url); 73554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (expectCached) { 73654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("1", request1.getHeaderField("X-Response-ID")); 73754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } else { 73854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("2", request2.getHeaderField("X-Response-ID")); 73954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void postInvalidatesCache() throws Exception { 74354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("POST"); 74454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 74654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void putInvalidatesCache() throws Exception { 74754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("PUT"); 74854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 74954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void deleteMethodInvalidatesCache() throws Exception { 75154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson testMethodInvalidates("DELETE"); 75254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 75354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 75454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void testMethodInvalidates(String requestMethod) throws Exception { 75554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. seed the cache 75654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. invalidate it 75754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 3. expect a cache miss 75854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 75954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().setBody("A").addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 76054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 76154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 76254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 76354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 76554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 76754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 76854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection invalidate = openConnection(url); 76954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setRequestMethod(requestMethod); 77054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson addRequestBodyIfNecessary(requestMethod, invalidate); 77154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(invalidate)); 77254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 77354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(openConnection(url))); 77454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 77554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 77654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etag() throws Exception { 77754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = 77854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached(new MockResponse().addHeader("ETag: v1")); 77954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1")); 78054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 78154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 78254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInThePast() throws Exception { 78354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 78454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 78554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v1") 78654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + lastModifiedDate) 78754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 78854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 78954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-None-Match: v1")); 79054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 79154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 79254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 79354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void etagAndExpirationDateInTheFuture() throws Exception { 79454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFullyCached(new MockResponse().addHeader("ETag: v1") 79554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 79654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 79754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 79854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 79954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCache() throws Exception { 80054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache")); 80154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 80254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 80354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoCacheAndExpirationDateInTheFuture() throws Exception { 80454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 80554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 80654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 80754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 80854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-cache")); 80954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 81054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 81154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 81254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 81354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCache() throws Exception { 81454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Pragma: no-cache")); 81554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 81654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 81754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void pragmaNoCacheAndExpirationDateInTheFuture() throws Exception { 81854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-2, TimeUnit.HOURS); 81954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest conditionalRequest = assertConditionallyCached( 82054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 82154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 82254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Pragma: no-cache")); 82354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = conditionalRequest.getHeaders(); 82454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate)); 82554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 82654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 82754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStore() throws Exception { 82854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Cache-Control: no-store")); 82954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 83054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 83154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cacheControlNoStoreAndExpirationDateInTheFuture() throws Exception { 83254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 83354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 83454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: no-store")); 83554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 83654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 83754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void partialRangeResponsesDoNotCorruptCache() throws Exception { 83854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 1. request a range 83954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // 2. request a full document, expecting a cache miss 84054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("AA") 84154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_PARTIAL) 84254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)) 84354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Range: bytes 1000-1001/2000")); 84454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("BB")); 84554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 84654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 84754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 84854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 84954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection range = openConnection(url); 85054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson range.addRequestProperty("Range", "bytes=1000-1001"); 85154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("AA", readAscii(range)); 85254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 85354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("BB", readAscii(openConnection(url))); 85454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 85554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 85654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void serverReturnsDocumentOlderThanCache() throws Exception { 85754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 85854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 85954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 86054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B") 86154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS))); 86254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 86354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 86454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 86554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 86654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 86754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 86854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 86954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 87054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndConditionalCache() throws Exception { 87154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 87254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 87354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))); 87454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 87554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 87654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void nonIdentityEncodingAndFullCache() throws Exception { 87754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNonIdentityEncodingCached( 87854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 87954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 88054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 88154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 88254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNonIdentityEncodingCached(MockResponse response) throws Exception { 88354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 88454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(gzip("ABCABCABC".getBytes("UTF-8"))).addHeader("Content-Encoding: gzip")); 88554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 88654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 88754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 88854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 88954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/")))); 89054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 89154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 89254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void expiresDateBeforeModifiedDate() throws Exception { 89354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertConditionallyCached( 89454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 89554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS))); 89654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 89754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 89854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxAge() throws IOException { 89954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 90054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS)) 90154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)) 90254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))); 90354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 90454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 90554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 90654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 90754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 90854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 90954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-age=30"); 91054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 91154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 91254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 91354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMinFresh() throws IOException { 91454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 91554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 91654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 91754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 91854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 91954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 92054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 92154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 92254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 92354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "min-fresh=120"); 92454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 92554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 92654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 92754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStale() throws IOException { 92854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 92954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120") 93054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 93154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 93254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 93354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 93454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 93554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 93654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 93754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 93854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 93954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("110 HttpURLConnection \"Response is stale\"", 94054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getHeaderField("Warning")); 94154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 94254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 94354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestMaxStaleNotHonoredWithMustRevalidate() throws IOException { 94454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 94554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=120, must-revalidate") 94654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES))); 94754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 94854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 94954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 95054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 95154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 95254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 95354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "max-stale=180"); 95454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 95554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 95654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 95754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithNoResponseCached() throws IOException { 95854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // (no responses enqueued) 95954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 96054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 96154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 96254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 96354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 96454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 96554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 96654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithFullResponseCached() throws IOException { 96754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 96854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 96954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 97054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 97154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 97254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 97354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 97454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 975faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 97654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 97754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 97854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithConditionalResponseCached() throws IOException { 97954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A") 98054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=30") 98154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))); 98254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 98354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 98454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 98554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 98654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 98754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 98854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 98954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 99054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException { 99154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 99254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 99354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 99454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 99554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 99654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Cache-Control", "only-if-cached"); 99754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertGatewayTimeout(connection); 99854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 99954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 100054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestCacheControlNoCache() throws Exception { 100154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 100254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 100354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 100454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 100554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 100654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 100754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 100854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 100954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 101054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 101154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 101254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Cache-Control", "no-cache"); 101354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 101454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 101554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 101654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void requestPragmaNoCache() throws Exception { 101754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 101854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS)) 101954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS)) 102054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 102154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 102254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 102354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 102454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 102554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 102654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 102754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 102854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setRequestProperty("Pragma", "no-cache"); 102954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 103054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 103154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 103254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfModifiedSinceWithCachedResult() throws Exception { 103354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = 103454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("ETag: v3").addHeader("Cache-Control: max-age=0"); 103554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS); 103654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = 103754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertClientSuppliedCondition(response, "If-Modified-Since", ifModifiedSinceDate); 103854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = request.getHeaders(); 103954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate)); 104054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(headers.contains("If-None-Match: v3")); 104154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 104254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 104354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception { 104454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES); 104554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson MockResponse response = new MockResponse().addHeader("Last-Modified: " + lastModifiedDate) 104654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES)) 104754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0"); 104854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = assertClientSuppliedCondition(response, "If-None-Match", "v1"); 104954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = request.getHeaders(); 105054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(headers.contains("If-None-Match: v1")); 105154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate)); 105254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 105354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 105454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName, 105554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String conditionValue) throws Exception { 105654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(seed.setBody("A")); 105754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 105854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 105954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 106054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 106154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 106254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 106354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(url); 106454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty(conditionName, conditionValue); 106554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 106654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 106754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 106854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // seed 106954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); 107054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 107154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 107254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void setIfModifiedSince() throws Exception { 107354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Date since = new Date(); 107454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("A")); 107554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 107654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 107754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 107854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 107954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setIfModifiedSince(since.getTime()); 108054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 108154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson RecordedRequest request = server.takeRequest(); 108254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(request.getHeaders().contains("If-Modified-Since: " + formatDate(since))); 108354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 108454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 108554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void clientSuppliedConditionWithoutCachedResult() throws Exception { 108654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 108754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 108854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 108954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection = openConnection(server.getUrl("/")); 109054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS); 109154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince); 109254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode()); 109354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("", readAscii(connection)); 109454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 109554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 109654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationRequestHeaderPreventsCaching() throws Exception { 109754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 109854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES)) 109954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60") 110054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 110154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 110254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 110354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 110454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 110554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 110654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Authorization", "password"); 110754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 110854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(url))); 110954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 111054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 111154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithSMaxAge() throws Exception { 111254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached( 111354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: s-maxage=60")); 111454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 111554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 111654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithPublic() throws Exception { 111754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached(new MockResponse().addHeader("Cache-Control: public")); 111854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 111954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 112054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void authorizationResponseCachedWithMustRevalidate() throws Exception { 112154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertAuthorizationRequestFullyCached( 112254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: must-revalidate")); 112354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 112454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 112554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception { 112654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.addHeader("Cache-Control: max-age=60").setBody("A")); 112754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 112854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 112954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 113054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 113154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(url); 113254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.addRequestProperty("Authorization", "password"); 113354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 113454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 113554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 113654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 113754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void contentLocationDoesNotPopulateCache() throws Exception { 113854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 113954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Location: /bar") 114054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 114154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 114254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 114354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 114454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/foo")))); 114554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/bar")))); 114654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 114754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 114854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotWriteToCache() throws Exception { 114954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 115054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 115154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 115254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 115354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 115454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 115554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 115654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection)); 115754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 115854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 115954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 116054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void useCachesFalseDoesNotReadFromCache() throws Exception { 116154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue( 116254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A").setBody("A")); 116354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 116454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 116554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 116654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 116754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection = openConnection(server.getUrl("/")); 116854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.setUseCaches(false); 116954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection)); 117054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 117154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 117254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void defaultUseCachesSetsInitialValueOnly() throws Exception { 117354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = new URL("http://localhost/"); 117454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c1 = openConnection(url); 117554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c2 = openConnection(url); 117654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getDefaultUseCaches()); 117754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(false); 117854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 117954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c1.getUseCaches()); 118054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertTrue(c2.getUseCaches()); 118154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection c3 = openConnection(url); 118254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertFalse(c3.getUseCaches()); 118354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } finally { 118454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson c1.setDefaultUseCaches(true); 118554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 118654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 118754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 118854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void connectionIsReturnedToPoolAfterConditionalSuccess() throws Exception { 118954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 119054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 119154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 119254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 119354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 119454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 119554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 119654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/a")))); 119754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/a")))); 119854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/b")))); 119954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 120054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, server.takeRequest().getSequenceNumber()); 120154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, server.takeRequest().getSequenceNumber()); 120254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.takeRequest().getSequenceNumber()); 120354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 120454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 120554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheMiss() throws Exception { 120654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 120754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 120854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 120954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 121054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("C")); 121154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 121254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 121354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 121454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 121554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 121654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 121754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 121854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(openConnection(server.getUrl("/")))); 121954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 122054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 122154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 122254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 122354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 122454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsConditionalCacheHit() throws Exception { 122554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 122654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 122754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 122854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 122954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 123054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 123154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 123254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 123354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 123454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 123554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 123654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 123754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 123854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 123954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getNetworkCount()); 124054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 124154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 124254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 124354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void statisticsFullCacheHit() throws Exception { 124454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60").setBody("A")); 124554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 124654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 124754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 124854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getRequestCount()); 124954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 125054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(0, cache.getHitCount()); 125154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 125254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 125354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(3, cache.getRequestCount()); 125454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(1, cache.getNetworkCount()); 125554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, cache.getHitCount()); 125654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 125754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 125854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesChangedRequestHeaderField() throws Exception { 125954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 126054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 126154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 126254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 126354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 126454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 126554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 126654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection frConnection = openConnection(url); 126754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 126854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 126954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 127054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection enConnection = openConnection(url); 127154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-US"); 127254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 127354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 127454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 127554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesUnchangedRequestHeaderField() throws Exception { 127654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 127754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 127854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 127954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 128054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 128154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 128254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 128354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 128454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 128554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 128654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 128754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 128854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 128954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 129054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 129154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAbsentRequestHeaderField() throws Exception { 129254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 129354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 129454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 129554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 129654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 129754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 129854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 129954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 130054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 130154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 130254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesAddedRequestHeaderField() throws Exception { 130354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 130454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 130554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 130654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 130754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 130854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 130954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 131054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection fooConnection = openConnection(server.getUrl("/")); 131154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 131254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(fooConnection)); 131354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 131454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 131554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMatchesRemovedRequestHeaderField() throws Exception { 131654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 131754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Foo") 131854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 131954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 132054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 132154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 132254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection fooConnection = openConnection(server.getUrl("/")); 132354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fooConnection.addRequestProperty("Foo", "bar"); 132454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(fooConnection)); 132554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 132654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 132754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 132854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyFieldsAreCaseInsensitive() throws Exception { 132954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 133054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: ACCEPT-LANGUAGE") 133154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 133254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 133354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 133454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 133554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 133654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 133754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 133854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 133954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 134054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("accept-language", "fr-CA"); 134154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 134254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 134354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 134454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithMatch() throws Exception { 134554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 134654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 134754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 134854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 134954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 135054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 135154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 135254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 135354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 135454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA"); 135554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Charset", "UTF-8"); 135654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Encoding", "identity"); 135754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 135854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 135954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 136054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Charset", "UTF-8"); 136154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Encoding", "identity"); 136254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 136354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 136454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 136554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldsWithNoMatch() throws Exception { 136654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 136754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language, Accept-Charset") 136854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Encoding") 136954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 137054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 137154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 137254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 137354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 137454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection frConnection = openConnection(url); 137554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Language", "fr-CA"); 137654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Charset", "UTF-8"); 137754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson frConnection.addRequestProperty("Accept-Encoding", "identity"); 137854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(frConnection)); 137954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection enConnection = openConnection(url); 138054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Language", "en-CA"); 138154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Charset", "UTF-8"); 138254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enConnection.addRequestProperty("Accept-Encoding", "identity"); 138354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(enConnection)); 138454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 138554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 138654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithMatch() throws Exception { 138754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 138854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 138954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 139054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 139154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 139254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 139354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 139454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 139554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 139654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 139754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 139854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 139954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 140054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 140154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 140254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 140354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 140454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 140554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyMultipleFieldValuesWithNoMatch() throws Exception { 140654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 140754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 140854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 140954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 141054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 141154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 141254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 141354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(url); 141454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR"); 141554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 141654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 141754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 141854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(url); 141954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "fr-CA"); 142054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 142154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection2)); 142254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 142354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 142454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAsterisk() throws Exception { 142554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 142654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: *") 142754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 142854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 142954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 143054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 143154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 143254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(server.getUrl("/")))); 143354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 143454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 143554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void varyAndHttps() throws Exception { 143654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.useHttps(sslContext.getSocketFactory(), false); 143754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=60") 143854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Vary: Accept-Language") 143954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 144054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 144154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 144254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 144354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 144454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection1 = (HttpsURLConnection) client.open(url); 144554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setSSLSocketFactory(sslContext.getSocketFactory()); 144654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 144754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection1.addRequestProperty("Accept-Language", "en-US"); 144854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 144954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 145054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpsURLConnection connection2 = (HttpsURLConnection) client.open(url); 145154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setSSLSocketFactory(sslContext.getSocketFactory()); 145254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.setHostnameVerifier(NULL_HOSTNAME_VERIFIER); 145354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection2.addRequestProperty("Accept-Language", "en-US"); 145454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 145554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 145654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 145754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusCookies() throws Exception { 145854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 145954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";") 146054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 146154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 146254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 146354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader( 146454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson "Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";") 146554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 146654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 146754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 146854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 146954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 147054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=FIRST"); 147154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 147254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertCookies(url, "a=SECOND"); 147354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 147454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 147554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsNetworkEndToEndHeaders() throws Exception { 147654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD") 147754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 147854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 147954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 148054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Allow: GET, HEAD, PUT") 148154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 148254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 148354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 148454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 148554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 148654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection1.getHeaderField("Allow")); 148754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 148854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 148954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 149054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD, PUT", connection2.getHeaderField("Allow")); 149154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 149254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 149354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersReturnsCachedHopByHopHeaders() throws Exception { 149454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: identity") 149554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 149654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 149754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 149854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Transfer-Encoding: none") 149954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 150054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 150154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 150254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 150354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 150454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection1.getHeaderField("Transfer-Encoding")); 150554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 150654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 150754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 150854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("identity", connection2.getHeaderField("Transfer-Encoding")); 150954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 151054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 151154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersDeletesCached100LevelWarnings() throws Exception { 151254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 199 test danger") 151354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 151454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 151554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 151654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 151754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 151854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 151954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 152054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 152154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("199 test danger", connection1.getHeaderField("Warning")); 152254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 152354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 152454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 152554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection2.getHeaderField("Warning")); 152654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 152754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 152854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void getHeadersRetainsCached200LevelWarnings() throws Exception { 152954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Warning: 299 test danger") 153054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS)) 153154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 153254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 153354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 153454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 153554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 153654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection1 = openConnection(server.getUrl("/")); 153754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 153854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection1.getHeaderField("Warning")); 153954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 154054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URLConnection connection2 = openConnection(server.getUrl("/")); 154154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 154254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("299 test danger", connection2.getHeaderField("Warning")); 154354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 154454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 154554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public void assertCookies(URL url, String... expectedCookies) throws Exception { 154654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> actualCookies = new ArrayList<String>(); 154754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (HttpCookie cookie : cookieManager.getCookieStore().get(url.toURI())) { 154854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson actualCookies.add(cookie.toString()); 154954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 155054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(Arrays.asList(expectedCookies), actualCookies); 155154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 155254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 155354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void cachePlusRange() throws Exception { 155454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertNotCached(new MockResponse().setResponseCode(HttpURLConnection.HTTP_PARTIAL) 155554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Date: " + formatDate(0, TimeUnit.HOURS)) 155654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Content-Range: bytes 100-100/200") 155754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=60")); 155854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 155954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 156054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Test public void conditionalHitUpdatesCache() throws Exception { 156154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS)) 156254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Cache-Control: max-age=0") 156354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setBody("A")); 156454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().addHeader("Cache-Control: max-age=30") 156554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .addHeader("Allow: GET, HEAD") 156654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 156754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 156854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 156954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 157054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // cache miss; seed the cache 157154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection1 = openConnection(server.getUrl("/a")); 157254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 157354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(null, connection1.getHeaderField("Allow")); 157454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 157554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // conditional cache hit; update the cache 157654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection2 = openConnection(server.getUrl("/a")); 157754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 157854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 157954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection2.getHeaderField("Allow")); 158054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 158154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson // full cache hit 158254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection3 = openConnection(server.getUrl("/a")); 158354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection3)); 158454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("GET, HEAD", connection3.getHeaderField("Allow")); 158554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 158654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(2, server.getRequestCount()); 158754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 158854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 1589faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderCached() throws IOException { 1590faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1591faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1592faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1593faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1594faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1595faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1596faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath URLConnection connection = openConnection(server.getUrl("/")); 1597faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath connection.addRequestProperty("Cache-Control", "only-if-cached"); 1598faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1599faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1600faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1601faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.CACHE.toString() + " 200", source); 1602faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1603faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1604faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheFetched() throws IOException { 1605faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1606faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1607faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(-31, TimeUnit.MINUTES))); 1608faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("B") 1609faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=30") 1610faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1611faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1612faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1613faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1614faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = openConnection(server.getUrl("/")); 1615faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("B", readAscii(connection)); 1616faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1617faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1618faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.CONDITIONAL_CACHE.toString() + " 200", source); 1619faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1620faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1621faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderConditionalCacheNotFetched() throws IOException { 1622faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A") 1623faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=0") 1624faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES))); 1625faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setResponseCode(304)); 1626faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1627faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1628faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(openConnection(server.getUrl("/")))); 1629faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = openConnection(server.getUrl("/")); 1630faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1631faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1632faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1633faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.CONDITIONAL_CACHE.toString() + " 304", source); 1634faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1635faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1636faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void responseSourceHeaderFetched() throws IOException { 1637faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse().setBody("A")); 1638faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1639faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1640faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath URLConnection connection = openConnection(server.getUrl("/")); 1641faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", readAscii(connection)); 1642faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1643faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath String source = connection.getHeaderField(ResponseHeaders.RESPONSE_SOURCE); 1644faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals(ResponseSource.NETWORK.toString() + " 200", source); 1645faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1646faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 1647faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath @Test public void emptyResponseHeaderNameFromCacheIsLenient() throws Exception { 1648faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.enqueue(new MockResponse() 1649faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader("Cache-Control: max-age=120") 1650faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .addHeader(": A") 1651faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath .setBody("body")); 1652faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath server.play(); 1653faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath HttpURLConnection connection = client.open(server.getUrl("/")); 1654faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath assertEquals("A", connection.getHeaderField("")); 1655faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath } 1656faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath 165754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 165854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * @param delta the offset from the current date to use. Negative 165954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * values yield dates in the past; positive values yield dates in the 166054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * future. 166154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 166254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(long delta, TimeUnit timeUnit) { 166354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta))); 166454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 166554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 166654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String formatDate(Date date) { 166754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); 166854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson rfc1123.setTimeZone(TimeZone.getTimeZone("UTC")); 166954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return rfc1123.format(date); 167054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 167154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 167254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void addRequestBodyIfNecessary(String requestMethod, HttpURLConnection invalidate) 167354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 167454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (requestMethod.equals("POST") || requestMethod.equals("PUT")) { 167554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson invalidate.setDoOutput(true); 167654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream requestBody = invalidate.getOutputStream(); 167754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.write('x'); 167854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson requestBody.close(); 167954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 168054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 168154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 168254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertNotCached(MockResponse response) throws Exception { 168354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 168454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(new MockResponse().setBody("B")); 168554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 168654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 168754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 168854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 168954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(openConnection(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 server.play(); 170354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 170454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL valid = server.getUrl("/valid"); 170554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection1 = openConnection(valid); 170654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection1)); 170754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection1.getResponseCode()); 170854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection1.getResponseMessage()); 170954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection2 = openConnection(valid); 171054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(connection2)); 171154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode()); 171254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A-OK", connection2.getResponseMessage()); 171354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 171454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL invalid = server.getUrl("/invalid"); 171554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection3 = openConnection(invalid); 171654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B", readAscii(connection3)); 171754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection3.getResponseCode()); 171854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("B-OK", connection3.getResponseMessage()); 171954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection connection4 = openConnection(invalid); 172054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C", readAscii(connection4)); 172154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(HttpURLConnection.HTTP_OK, connection4.getResponseCode()); 172254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("C-OK", connection4.getResponseMessage()); 172354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 172454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.takeRequest(); // regular get 172554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return server.takeRequest(); // conditional get 172654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 172754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 172854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertFullyCached(MockResponse response) throws Exception { 172954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("A")); 173054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.enqueue(response.setBody("B")); 173154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson server.play(); 173254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 173354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson URL url = server.getUrl("/"); 173454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 173554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals("A", readAscii(openConnection(url))); 173654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 173754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 173854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 173954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Shortens the body of {@code response} but not the corresponding headers. 174054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Only useful to test how clients respond to the premature conclusion of 174154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * the HTTP body. 174254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 174354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 174454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setSocketPolicy(DISCONNECT_AT_END); 174554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson List<String> headers = new ArrayList<String>(response.getHeaders()); 174654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 174754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.getHeaders().clear(); 174854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.getHeaders().addAll(headers); 174954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response; 175054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 175154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 175254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** 175354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * Reads {@code count} characters from the stream. If the stream is 175454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * exhausted before {@code count} characters can be read, the remaining 175554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson * characters are returned and the stream is closed. 175654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson */ 175754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection, int count) throws IOException { 175854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson HttpURLConnection httpConnection = (HttpURLConnection) connection; 175954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST 176054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ? connection.getInputStream() : httpConnection.getErrorStream(); 176154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson StringBuilder result = new StringBuilder(); 176254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (int i = 0; i < count; i++) { 176354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson int value = in.read(); 176454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (value == -1) { 17657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath in.close(); 176654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 176754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 176854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson result.append((char) value); 176954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 177054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return result.toString(); 177154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 177254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 177354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private String readAscii(URLConnection connection) throws IOException { 177454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return readAscii(connection, Integer.MAX_VALUE); 177554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 177654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 177754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void reliableSkip(InputStream in, int length) throws IOException { 177854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson while (length > 0) { 177954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson length -= in.skip(length); 178054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 178154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 178254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 178354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private void assertGatewayTimeout(HttpURLConnection connection) throws IOException { 178454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson try { 178554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson connection.getInputStream(); 178654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson fail(); 178754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } catch (FileNotFoundException expected) { 178854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 178954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(504, connection.getResponseCode()); 179054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson assertEquals(-1, connection.getErrorStream().read()); 179154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 179254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 179354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson enum TransferKind { 179454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson CHUNKED() { 179554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) 179654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson throws IOException { 179754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setChunkedBody(content, chunkSize); 179854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 179954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 180054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson FIXED_LENGTH() { 180154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 180254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 180354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 180454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }, 180554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson END_OF_STREAM() { 180654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 180754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson response.setBody(content); 18087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath response.setSocketPolicy(DISCONNECT_AT_END); 180954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 181054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (h.next().startsWith("Content-Length:")) { 181154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson h.remove(); 181254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson break; 181354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 181554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 181654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson }; 18177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath 181854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson abstract void setBody(MockResponse response, byte[] content, int chunkSize) throws IOException; 181954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 182054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson void setBody(MockResponse response, String content, int chunkSize) throws IOException { 182154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson setBody(response, content.getBytes("UTF-8"), chunkSize); 182254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 182354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 182454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 182554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private <T> List<T> toListOrNull(T[] arrayOrNull) { 182654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null; 182754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 182854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 182954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson /** Returns a gzipped copy of {@code bytes}. */ 183054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson public byte[] gzip(byte[] bytes) throws IOException { 183154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 183254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 183354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson gzippedOut.write(bytes); 183454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson gzippedOut.close(); 183554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return bytesOut.toByteArray(); 183654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 183754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 183854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson private class InsecureResponseCache extends ResponseCache { 183954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 184054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return cache.put(uri, connection); 184154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 184254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson 184354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public CacheResponse get(URI uri, String requestMethod, 184454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson Map<String, List<String>> requestHeaders) throws IOException { 184554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson final CacheResponse response = cache.get(uri, requestMethod, requestHeaders); 184654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson if (response instanceof SecureCacheResponse) { 184754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return new CacheResponse() { 184854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public InputStream getBody() throws IOException { 184954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response.getBody(); 185054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 185154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson @Override public Map<String, List<String>> getHeaders() throws IOException { 185254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response.getHeaders(); 185354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath }; 185554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 185654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson return response; 18577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath } 185854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson } 18597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath} 1860