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