ResponseCacheTest.java revision 7899c5ab935cf542069835ec7d3e457db596dbf7
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
177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathpackage libcore.net.http;
187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.MockResponse;
207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.MockWebServer;
217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.google.mockwebserver.RecordedRequest;
227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport com.squareup.okhttp.OkHttpConnection;
237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.BufferedReader;
247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.ByteArrayOutputStream;
257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.File;
267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.FileNotFoundException;
277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.IOException;
287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStream;
297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.InputStreamReader;
307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.io.OutputStream;
317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CacheRequest;
327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.CacheResponse;
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.SecureCacheResponse;
397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URI;
407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URISyntaxException;
417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URL;
427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.net.URLConnection;
437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.DateFormat;
447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.text.SimpleDateFormat;
457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.ArrayList;
467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Arrays;
477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Collections;
487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Date;
497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Iterator;
507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.List;
517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Locale;
527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.Map;
537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.TimeZone;
547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.UUID;
557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.TimeUnit;
567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.atomic.AtomicInteger;
577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.concurrent.atomic.AtomicReference;
587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport java.util.zip.GZIPOutputStream;
597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport junit.framework.TestCase;
607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathimport static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_END;
627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath/**
647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath * Android's HttpResponseCacheTest.
657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath */
667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamathpublic final class HttpResponseCacheTest extends TestCase {
677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private MockWebServer server = new MockWebServer();
687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private HttpResponseCache cache;
697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    private final MockOs mockOs = new MockOs();
707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private final CookieManager cookieManager = new CookieManager();
717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    @Override protected void setUp() throws Exception {
737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        super.setUp();
747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String tmp = System.getProperty("java.io.tmpdir");
767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID());
777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE);
787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        ResponseCache.setDefault(cache);
797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        mockOs.install();
807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        CookieHandler.setDefault(cookieManager);
817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    @Override protected void tearDown() throws Exception {
847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        mockOs.uninstall();
857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.shutdown();
867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        ResponseCache.setDefault(null);
877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        cache.getCache().delete();
887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        CookieHandler.setDefault(null);
897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        super.tearDown();
907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private static OkHttpConnection openConnection(URL url) {
937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return OkHttpConnection.open(url);
947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Test that response caching is consistent with the RI and the spec.
987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4
997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
1007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testResponseCachingByResponseCode() throws Exception {
1017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // Test each documented HTTP/1.1 code, plus the first unused value in each range.
1027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
1037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // We can't test 100 because it's not really a response.
1057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // assertCached(false, 100);
1067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 101);
1077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 102);
1087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(true,  200);
1097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 201);
1107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 202);
1117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(true,  203);
1127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 204);
1137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 205);
1147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 206); // we don't cache partial responses
1157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 207);
1167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(true,  300);
1177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(true,  301);
1187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        for (int i = 302; i <= 308; ++i) {
1197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertCached(false, i);
1207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
1217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        for (int i = 400; i <= 406; ++i) {
1227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertCached(false, i);
1237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
1247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // (See test_responseCaching_407.)
1257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 408);
1267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(false, 409);
1277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // (See test_responseCaching_410.)
1287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        for (int i = 411; i <= 418; ++i) {
1297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertCached(false, i);
1307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
1317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        for (int i = 500; i <= 506; ++i) {
1327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertCached(false, i);
1337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
1347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
1357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
1377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Response code 407 should only come from proxy servers. Android's client
1387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * throws if it is sent by an origin server.
1397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
1407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testOriginServerSends407() throws Exception {
1417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setResponseCode(407));
1427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
1437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
1457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection conn = openConnection(url);
1467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        try {
1477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            conn.getResponseCode();
1487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            fail();
1497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } catch (IOException expected) {
1507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
1517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
1527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void test_responseCaching_410() throws Exception {
1547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // the HTTP spec permits caching 410s, but the RI doesn't.
1557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCached(true, 410);
1567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
1577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void assertCached(boolean shouldPut, int responseCode) throws Exception {
1597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server = new MockWebServer();
1607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        MockResponse response = new MockResponse()
1617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
1627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
1637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(responseCode)
1647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("ABCDE")
1657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("WWW-Authenticate: challenge");
1667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if (responseCode == HttpURLConnection.HTTP_PROXY_AUTH) {
1677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            response.addHeader("Proxy-Authenticate: Basic realm=\"protected area\"");
1687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
1697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            response.addHeader("WWW-Authenticate: Basic realm=\"protected area\"");
1707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
1717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response);
1727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
1737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
1757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection conn = openConnection(url);
1767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(responseCode, conn.getResponseCode());
1777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // exhaust the content stream
1797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        readAscii(conn);
1807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        CacheResponse cached = cache.get(url.toURI(), "GET",
1827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                Collections.<String, List<String>>emptyMap());
1837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if (shouldPut) {
1847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertNotNull(Integer.toString(responseCode), cached);
1857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            cached.getBody().close();
1867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } else {
1877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertNull(Integer.toString(responseCode), cached);
1887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
1897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers
1907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
1917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
1927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
1937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Test that we can interrogate the response when the cache is being
1947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * populated. http://code.google.com/p/android/issues/detail?id=7787
1957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
1967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testResponseCacheCallbackApis() throws Exception {
1977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        final String body = "ABCDE";
1987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        final AtomicInteger cacheCount = new AtomicInteger();
1997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
2017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setStatus("HTTP/1.1 200 Fantastic")
2027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("fgh: ijk")
2037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody(body));
2047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
2057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        ResponseCache.setDefault(new ResponseCache() {
2077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            @Override public CacheResponse get(URI uri, String requestMethod,
2087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    Map<String, List<String>> requestHeaders) throws IOException {
2097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                return null;
2107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
2117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException {
2127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                OkHttpConnection httpConnection = (OkHttpConnection) conn;
2137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                try {
2147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    httpConnection.getRequestProperties();
2157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    fail();
2167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                } catch (IllegalStateException expected) {
2177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                }
2187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                try {
2197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    httpConnection.addRequestProperty("K", "V");
2207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    fail();
2217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                } catch (IllegalStateException expected) {
2227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                }
2237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                assertEquals("HTTP/1.1 200 Fantastic", httpConnection.getHeaderField(null));
2247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                assertEquals(Arrays.asList("HTTP/1.1 200 Fantastic"),
2257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                        httpConnection.getHeaderFields().get(null));
2267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                assertEquals(200, httpConnection.getResponseCode());
2277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                assertEquals("Fantastic", httpConnection.getResponseMessage());
2287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                assertEquals(body.length(), httpConnection.getContentLength());
2297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                assertEquals("ijk", httpConnection.getHeaderField("fgh"));
2307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                try {
2317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    httpConnection.getInputStream(); // the RI doesn't forbid this, but it should
2327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    fail();
2337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                } catch (IOException expected) {
2347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                }
2357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                cacheCount.incrementAndGet();
2367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                return null;
2377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
2387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        });
2397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
2417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection = openConnection(url);
2427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(body, readAscii(connection));
2437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cacheCount.get());
2447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
2457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testResponseCachingAndInputStreamSkipWithFixedLength() throws IOException {
2487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testResponseCaching(TransferKind.FIXED_LENGTH);
2497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
2507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testResponseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException {
2527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testResponseCaching(TransferKind.CHUNKED);
2537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
2547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testResponseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException {
2567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testResponseCaching(TransferKind.END_OF_STREAM);
2577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
2587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
2607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption
2617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * http://code.google.com/p/android/issues/detail?id=8175
2627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
2637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void testResponseCaching(TransferKind transferKind) throws IOException {
2647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        MockResponse response = new MockResponse()
2657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
2667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
2677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setStatus("HTTP/1.1 200 Fantastic");
2687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        transferKind.setBody(response, "I love puppies but hate spiders", 1);
2697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response);
2707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
2717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // Make sure that calling skip() doesn't omit bytes from the cache.
2737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection urlConnection = openConnection(server.getUrl("/"));
2747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        InputStream in = urlConnection.getInputStream();
2757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("I love ", readAscii(urlConnection, "I love ".length()));
2767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        reliableSkip(in, "puppies but hate ".length());
2777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("spiders", readAscii(urlConnection, "spiders".length()));
2787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(-1, in.read());
2797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        in.close();
2807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteSuccessCount());
2817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getWriteAbortCount());
2827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        urlConnection = openConnection(server.getUrl("/")); // cached!
2847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        in = urlConnection.getInputStream();
2857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("I love puppies but hate spiders",
2867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                readAscii(urlConnection, "I love puppies but hate spiders".length()));
2877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(200, urlConnection.getResponseCode());
2887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("Fantastic", urlConnection.getResponseMessage());
2897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(-1, in.read());
2917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        in.close();
2927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteSuccessCount());
2937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getWriteAbortCount());
2947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, cache.getRequestCount());
2957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getHitCount());
2967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
2977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
2987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    public void testSecureResponseCaching() throws IOException {
2997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        TestSSLContext testSSLContext = TestSSLContext.create();
3007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
3017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse()
3027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
3037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
3047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .setBody("ABC"));
3057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.play();
3067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
3087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
3097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("ABC", readAscii(connection));
3107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        // OpenJDK 6 fails on this line, complaining that the connection isn't open yet
3127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        String suite = connection.getCipherSuite();
3137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        List<Certificate> localCerts = toListOrNull(connection.getLocalCertificates());
3147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        List<Certificate> serverCerts = toListOrNull(connection.getServerCertificates());
3157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        Principal peerPrincipal = connection.getPeerPrincipal();
3167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        Principal localPrincipal = connection.getLocalPrincipal();
3177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached!
3197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
3207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("ABC", readAscii(connection));
3217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(2, cache.getRequestCount());
3237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(1, cache.getNetworkCount());
3247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(1, cache.getHitCount());
3257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(suite, connection.getCipherSuite());
3277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(localCerts, toListOrNull(connection.getLocalCertificates()));
3287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(serverCerts, toListOrNull(connection.getServerCertificates()));
3297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(peerPrincipal, connection.getPeerPrincipal());
3307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(localPrincipal, connection.getLocalPrincipal());
3317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    }
3327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    public void testCacheReturnsInsecureResponseForSecureRequest() throws IOException {
3347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        TestSSLContext testSSLContext = TestSSLContext.create();
3357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
3367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse().setBody("ABC"));
3377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse().setBody("DEF"));
3387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.play();
3397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        ResponseCache.setDefault(new InsecureResponseCache());
3417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
3437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
3447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("ABC", readAscii(connection));
3457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
3467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // not cached!
3477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
3487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("DEF", readAscii(connection));
3497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    }
3507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testResponseCachingAndRedirects() throws Exception {
3527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
3537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
3547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
3557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM)
3567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Location: /foo"));
3577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
3587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
3597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
3607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("ABC"));
3617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("DEF"));
3627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
3637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection = openConnection(server.getUrl("/"));
3657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABC", readAscii(connection));
3667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection = openConnection(server.getUrl("/")); // cached!
3687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABC", readAscii(connection));
3697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(4, cache.getRequestCount()); // 2 requests + 2 redirects
3717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, cache.getNetworkCount());
3727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, cache.getHitCount());
3737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
3747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRedirectToCachedResult() throws Exception {
3767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
3777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
3787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("ABC"));
3797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
3807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM)
3817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Location: /foo"));
3827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("DEF"));
3837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
3847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABC", readAscii(openConnection(server.getUrl("/foo"))));
3867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest request1 = server.takeRequest();
3877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("GET /foo HTTP/1.1", request1.getRequestLine());
3887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, request1.getSequenceNumber());
3897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABC", readAscii(openConnection(server.getUrl("/bar"))));
3917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest request2 = server.takeRequest();
3927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("GET /bar HTTP/1.1", request2.getRequestLine());
3937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, request2.getSequenceNumber());
3947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
3957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // an unrelated request should reuse the pooled connection
3967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("DEF", readAscii(openConnection(server.getUrl("/baz"))));
3977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest request3 = server.takeRequest();
3987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("GET /baz HTTP/1.1", request3.getRequestLine());
3997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, request3.getSequenceNumber());
4007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
4017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    public void testSecureResponseCachingAndRedirects() throws IOException {
4037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        TestSSLContext testSSLContext = TestSSLContext.create();
4047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
4057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse()
4067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
4077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
4087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .setResponseCode(HttpURLConnection.HTTP_MOVED_PERM)
4097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Location: /foo"));
4107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse()
4117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
4127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
4137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .setBody("ABC"));
4147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse().setBody("DEF"));
4157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.play();
4167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
4177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
4187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
4197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("ABC", readAscii(connection));
4207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
4217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection = (HttpsURLConnection) server.getUrl("/").openConnection(); // cached!
4227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
4237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("ABC", readAscii(connection));
4247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
4257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(4, cache.getRequestCount()); // 2 direct + 2 redirect = 4
4267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals(2, cache.getHitCount());
4277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    }
4287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testResponseCacheRequestHeaders() throws IOException, URISyntaxException {
4307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("ABC"));
4317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
4327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        final AtomicReference<Map<String, List<String>>> requestHeadersRef
4347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                = new AtomicReference<Map<String, List<String>>>();
4357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        ResponseCache.setDefault(new ResponseCache() {
4367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            @Override public CacheResponse get(URI uri, String requestMethod,
4377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    Map<String, List<String>> requestHeaders) throws IOException {
4387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                requestHeadersRef.set(requestHeaders);
4397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                return null;
4407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
4417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            @Override public CacheRequest put(URI uri, URLConnection conn) throws IOException {
4427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                return null;
4437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
4447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        });
4457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
4477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection urlConnection = openConnection(url);
4487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        urlConnection.addRequestProperty("A", "android");
4497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        readAscii(urlConnection);
4507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(Arrays.asList("android"), requestHeadersRef.get().get("A"));
4517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
4527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testServerDisconnectsPrematurelyWithContentLengthHeader() throws IOException {
4557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testServerPrematureDisconnect(TransferKind.FIXED_LENGTH);
4567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
4577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testServerDisconnectsPrematurelyWithChunkedEncoding() throws IOException {
4597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testServerPrematureDisconnect(TransferKind.CHUNKED);
4607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
4617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testServerDisconnectsPrematurelyWithNoLengthHeaders() throws IOException {
4637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        /*
4647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * Intentionally empty. This case doesn't make sense because there's no
4657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * such thing as a premature disconnect when the disconnect itself
4667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * indicates the end of the data stream.
4677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         */
4687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
4697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException {
4717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        MockResponse response = new MockResponse();
4727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16);
4737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(truncateViolently(response, 16));
4747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("Request #2"));
4757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
4767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        BufferedReader reader = new BufferedReader(new InputStreamReader(
4787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                openConnection(server.getUrl("/")).getInputStream()));
4797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABCDE", reader.readLine());
4807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        try {
4817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            reader.readLine();
4827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            fail("This implementation silently ignored a truncated HTTP body.");
4837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } catch (IOException expected) {
4847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } finally {
4857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            reader.close();
4867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
4877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteAbortCount());
4897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getWriteSuccessCount());
4907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
4917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("Request #2", readAscii(connection));
4927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteAbortCount());
4937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteSuccessCount());
4947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
4957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
4967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testClientPrematureDisconnectWithContentLengthHeader() throws IOException {
4977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testClientPrematureDisconnect(TransferKind.FIXED_LENGTH);
4987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
4997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testClientPrematureDisconnectWithChunkedEncoding() throws IOException {
5017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testClientPrematureDisconnect(TransferKind.CHUNKED);
5027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testClientPrematureDisconnectWithNoLengthHeaders() throws IOException {
5057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testClientPrematureDisconnect(TransferKind.END_OF_STREAM);
5067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException {
5097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        MockResponse response = new MockResponse();
5107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024);
5117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response);
5127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("Request #2"));
5137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
5147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
5167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        InputStream in = connection.getInputStream();
5177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABCDE", readAscii(connection, 5));
5187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        in.close();
5197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        try {
5207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            in.read();
5217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            fail("Expected an IOException because the stream is closed.");
5227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } catch (IOException expected) {
5237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
5247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteAbortCount());
5267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getWriteSuccessCount());
5277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection = openConnection(server.getUrl("/"));
5287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("Request #2", readAscii(connection));
5297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteAbortCount());
5307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getWriteSuccessCount());
5317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testDefaultExpirationDateFullyCachedForLessThan24Hours() throws Exception {
5347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //      last modified: 105 seconds ago
5357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //             served:   5 seconds ago
5367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //   default lifetime: (105 - 5) / 10 = 10 seconds
5377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //            expires:  10 seconds from served date = 5 seconds from now
5387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
5397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS))
5407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS))
5417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
5427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
5437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
5457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
5467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(url);
5477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection));
5487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNull(connection.getHeaderField("Warning"));
5497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testDefaultExpirationDateConditionallyCached() throws Exception {
5527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //      last modified: 115 seconds ago
5537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //             served:  15 seconds ago
5547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //   default lifetime: (115 - 15) / 10 = 10 seconds
5557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //            expires:  10 seconds from served date = 5 seconds ago
5567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String lastModifiedDate = formatDate(-115, TimeUnit.SECONDS);
5577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse()
5587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + lastModifiedDate)
5597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-15, TimeUnit.SECONDS)));
5607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = conditionalRequest.getHeaders();
5617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate));
5627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testDefaultExpirationDateFullyCachedForMoreThan24Hours() throws Exception {
5657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //      last modified: 105 days ago
5667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //             served:   5 days ago
5677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //   default lifetime: (105 - 5) / 10 = 10 days
5687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        //            expires:  10 days from served date = 5 days from now
5697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
5707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.DAYS))
5717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-5, TimeUnit.DAYS))
5727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
5737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
5747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
5767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
5777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection));
5787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("113 HttpURLConnection \"Heuristic expiration\"",
5797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                connection.getHeaderField("Warning"));
5807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testNoDefaultExpirationForUrlsWithQueryString() throws Exception {
5837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
5847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-105, TimeUnit.SECONDS))
5857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-5, TimeUnit.SECONDS))
5867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
5877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
5887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
5897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/?foo=bar");
5917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
5927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(url)));
5937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
5947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
5957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testExpirationDateInThePastWithLastModifiedHeader() throws Exception {
5967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String lastModifiedDate = formatDate(-2, TimeUnit.HOURS);
5977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse()
5987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + lastModifiedDate)
5997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)));
6007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = conditionalRequest.getHeaders();
6017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate));
6027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testExpirationDateInThePastWithNoLastModifiedHeader() throws Exception {
6057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse()
6067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)));
6077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testExpirationDateInTheFuture() throws Exception {
6107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
6117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)));
6127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgePreferredWithMaxAgeAndExpires() throws Exception {
6157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
6167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.HOURS))
6177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS))
6187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgeInThePastWithDateAndLastModifiedHeaders() throws Exception {
6227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String lastModifiedDate = formatDate(-2, TimeUnit.HOURS);
6237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse()
6247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS))
6257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + lastModifiedDate)
6267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = conditionalRequest.getHeaders();
6287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate));
6297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgeInThePastWithDateHeaderButNoLastModifiedHeader() throws Exception {
6327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        /*
6337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * Chrome interprets max-age relative to the local clock. Both our cache
6347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * and Firefox both use the earlier of the local and server's clock.
6357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         */
6367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse()
6377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-120, TimeUnit.SECONDS))
6387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgeInTheFutureWithDateHeader() throws Exception {
6427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
6437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.HOURS))
6447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgeInTheFutureWithNoDateHeader() throws Exception {
6487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
6497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgeWithLastModifiedButNoServedDate() throws Exception {
6537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
6547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS))
6557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgeInTheFutureWithDateAndLastModifiedHeaders() throws Exception {
6597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
6607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS))
6617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS))
6627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgePreferredOverLowerSharedMaxAge() throws Exception {
6667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
6677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES))
6687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: s-maxage=60")
6697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=180"));
6707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testMaxAgePreferredOverHigherMaxAge() throws Exception {
6737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse()
6747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES))
6757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: s-maxage=180")
6767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
6777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMethodOptionsIsNotCached() throws Exception {
6807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testRequestMethod("OPTIONS", false);
6817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMethodGetIsCached() throws Exception {
6847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testRequestMethod("GET", true);
6857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMethodHeadIsNotCached() throws Exception {
6887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // We could support this but choose not to for implementation simplicity
6897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testRequestMethod("HEAD", false);
6907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMethodPostIsNotCached() throws Exception {
6937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // We could support this but choose not to for implementation simplicity
6947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testRequestMethod("POST", false);
6957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
6967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
6977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMethodPutIsNotCached() throws Exception {
6987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testRequestMethod("PUT", false);
6997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMethodDeleteIsNotCached() throws Exception {
7027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testRequestMethod("DELETE", false);
7037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMethodTraceIsNotCached() throws Exception {
7067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testRequestMethod("TRACE", false);
7077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void testRequestMethod(String requestMethod, boolean expectCached) throws Exception {
7107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        /*
7117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * 1. seed the cache (potentially)
7127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * 2. expect a cache hit or miss
7137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         */
7147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
7157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
7167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("X-Response-ID: 1"));
7177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
7187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("X-Response-ID: 2"));
7197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
7207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
7227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection request1 = (OkHttpConnection) openConnection(url);
7247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        request1.setRequestMethod(requestMethod);
7257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        addRequestBodyIfNecessary(requestMethod, request1);
7267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("1", request1.getHeaderField("X-Response-ID"));
7277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection request2 = openConnection(url);
7297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if (expectCached) {
7307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertEquals("1", request1.getHeaderField("X-Response-ID"));
7317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } else {
7327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertEquals("2", request2.getHeaderField("X-Response-ID"));
7337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
7347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testPostInvalidatesCache() throws Exception {
7377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testMethodInvalidates("POST");
7387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testPutInvalidatesCache() throws Exception {
7417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testMethodInvalidates("PUT");
7427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testDeleteMethodInvalidatesCache() throws Exception {
7457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        testMethodInvalidates("DELETE");
7467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void testMethodInvalidates(String requestMethod) throws Exception {
7497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        /*
7507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * 1. seed the cache
7517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * 2. invalidate it
7527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * 3. expect a cache miss
7537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         */
7547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
7557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)));
7567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
7577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("C"));
7587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
7597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
7617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
7637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection invalidate = openConnection(url);
7657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        invalidate.setRequestMethod(requestMethod);
7667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        addRequestBodyIfNecessary(requestMethod, invalidate);
7677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(invalidate));
7687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("C", readAscii(openConnection(url)));
7707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testEtag() throws Exception {
7737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse()
7747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("ETag: v1"));
7757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(conditionalRequest.getHeaders().contains("If-None-Match: v1"));
7767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testEtagAndExpirationDateInThePast() throws Exception {
7797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String lastModifiedDate = formatDate(-2, TimeUnit.HOURS);
7807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse()
7817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("ETag: v1")
7827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + lastModifiedDate)
7837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)));
7847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = conditionalRequest.getHeaders();
7857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-None-Match: v1"));
7867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate));
7877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testEtagAndExpirationDateInTheFuture() throws Exception {
7907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFullyCached(new MockResponse()
7917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("ETag: v1")
7927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS))
7937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)));
7947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
7967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testCacheControlNoCache() throws Exception {
7977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse().addHeader("Cache-Control: no-cache"));
7987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
7997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testCacheControlNoCacheAndExpirationDateInTheFuture() throws Exception {
8017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String lastModifiedDate = formatDate(-2, TimeUnit.HOURS);
8027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse()
8037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + lastModifiedDate)
8047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
8057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: no-cache"));
8067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = conditionalRequest.getHeaders();
8077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate));
8087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testPragmaNoCache() throws Exception {
8117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse().addHeader("Pragma: no-cache"));
8127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testPragmaNoCacheAndExpirationDateInTheFuture() throws Exception {
8157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String lastModifiedDate = formatDate(-2, TimeUnit.HOURS);
8167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest conditionalRequest = assertConditionallyCached(new MockResponse()
8177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + lastModifiedDate)
8187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
8197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Pragma: no-cache"));
8207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = conditionalRequest.getHeaders();
8217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-Modified-Since: " + lastModifiedDate));
8227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testCacheControlNoStore() throws Exception {
8257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse().addHeader("Cache-Control: no-store"));
8267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testCacheControlNoStoreAndExpirationDateInTheFuture() throws Exception {
8297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse()
8307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS))
8317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
8327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: no-store"));
8337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testPartialRangeResponsesDoNotCorruptCache() throws Exception {
8367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        /*
8377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * 1. request a range
8387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         * 2. request a full document, expecting a cache miss
8397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath         */
8407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("AA")
8417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_PARTIAL)
8427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS))
8437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Content-Range: bytes 1000-1001/2000"));
8447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("BB"));
8457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
8467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
8487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection range = openConnection(url);
8507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        range.addRequestProperty("Range", "bytes=1000-1001");
8517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("AA", readAscii(range));
8527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("BB", readAscii(openConnection(url)));
8547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testServerReturnsDocumentOlderThanCache() throws Exception {
8577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
8587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS))
8597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)));
8607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B")
8617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-4, TimeUnit.HOURS)));
8627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
8637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
8657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
8677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
8687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testNonIdentityEncodingAndConditionalCache() throws Exception {
8717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNonIdentityEncodingCached(new MockResponse()
8727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS))
8737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(-1, TimeUnit.HOURS)));
8747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testNonIdentityEncodingAndFullCache() throws Exception {
8777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNonIdentityEncodingCached(new MockResponse()
8787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS))
8797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)));
8807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void assertNonIdentityEncodingCached(MockResponse response) throws Exception {
8837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response
8847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody(gzip("ABCABCABC".getBytes("UTF-8")))
8857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Content-Encoding: gzip"));
8867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
8877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
8897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/"))));
8907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("ABCABCABC", readAscii(openConnection(server.getUrl("/"))));
8917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testExpiresDateBeforeModifiedDate() throws Exception {
8947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertConditionallyCached(new MockResponse()
8957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
8967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(-2, TimeUnit.HOURS)));
8977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
8987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
8997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMaxAge() throws IOException {
9007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
9017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.HOURS))
9027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES))
9037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Expires: " + formatDate(1, TimeUnit.HOURS)));
9047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
9057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
9107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "max-age=30");
9117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection));
9127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
9137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMinFresh() throws IOException {
9157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
9167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
9177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES)));
9187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
9197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
9247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "min-fresh=120");
9257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection));
9267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
9277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMaxStale() throws IOException {
9297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
9307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=120")
9317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES)));
9327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
9337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
9387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "max-stale=180");
9397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection));
9407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("110 HttpURLConnection \"Response is stale\"",
9417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                connection.getHeaderField("Warning"));
9427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
9437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestMaxStaleNotHonoredWithMustRevalidate() throws IOException {
9457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
9467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=120, must-revalidate")
9477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-4, TimeUnit.MINUTES)));
9487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
9497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
9547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "max-stale=180");
9557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection));
9567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
9577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestOnlyIfCachedWithNoResponseCached() throws IOException {
9597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // (no responses enqueued)
9607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection = openConnection(server.getUrl("/"));
9637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "only-if-cached");
9647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertGatewayTimeout(connection);
9657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
9667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestOnlyIfCachedWithFullResponseCached() throws IOException {
9687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
9697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=30")
9707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.MINUTES)));
9717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
9757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "only-if-cached");
9767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
9787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestOnlyIfCachedWithConditionalResponseCached() throws IOException {
9807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A")
9817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=30")
9827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-1, TimeUnit.MINUTES)));
9837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection = openConnection(server.getUrl("/"));
9877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "only-if-cached");
9887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertGatewayTimeout(connection);
9897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
9907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestOnlyIfCachedWithUnhelpfulResponseCached() throws IOException {
9927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A"));
9937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
9947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
9957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
9967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection = openConnection(server.getUrl("/"));
9977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Cache-Control", "only-if-cached");
9987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertGatewayTimeout(connection);
9997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
10007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestCacheControlNoCache() throws Exception {
10027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
10037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS))
10047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS))
10057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
10067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
10077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
10087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
10097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
10117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
10127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(url);
10137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.setRequestProperty("Cache-Control", "no-cache");
10147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection));
10157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
10167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testRequestPragmaNoCache() throws Exception {
10187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
10197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-120, TimeUnit.SECONDS))
10207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.SECONDS))
10217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
10227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
10237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
10247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
10257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
10277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
10287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(url);
10297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.setRequestProperty("Pragma", "no-cache");
10307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection));
10317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
10327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testClientSuppliedIfModifiedSinceWithCachedResult() throws Exception {
10347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        MockResponse response = new MockResponse()
10357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("ETag: v3")
10367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0");
10377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String ifModifiedSinceDate = formatDate(-24, TimeUnit.HOURS);
10387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest request = assertClientSuppliedCondition(
10397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                response, "If-Modified-Since", ifModifiedSinceDate);
10407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = request.getHeaders();
10417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-Modified-Since: " + ifModifiedSinceDate));
10427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFalse(headers.contains("If-None-Match: v3"));
10437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
10447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testClientSuppliedIfNoneMatchSinceWithCachedResult() throws Exception {
10467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String lastModifiedDate = formatDate(-3, TimeUnit.MINUTES);
10477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        MockResponse response = new MockResponse()
10487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + lastModifiedDate)
10497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(-2, TimeUnit.MINUTES))
10507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0");
10517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest request = assertClientSuppliedCondition(
10527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                response, "If-None-Match", "v1");
10537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = request.getHeaders();
10547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(headers.contains("If-None-Match: v1"));
10557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertFalse(headers.contains("If-Modified-Since: " + lastModifiedDate));
10567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
10577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private RecordedRequest assertClientSuppliedCondition(MockResponse seed, String conditionName,
10597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            String conditionValue) throws Exception {
10607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(seed.setBody("A"));
10617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
10627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
10637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
10657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
10667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection = openConnection(url);
10687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty(conditionName, conditionValue);
10697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode());
10707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("", readAscii(connection));
10717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.takeRequest(); // seed
10737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return server.takeRequest();
10747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
10757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testSetIfModifiedSince() throws Exception {
10777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        Date since = new Date();
10787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("A"));
10797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
10807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
10827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(url);
10837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.setIfModifiedSince(since.getTime());
10847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection));
10857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        RecordedRequest request = server.takeRequest();
10867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(request.getHeaders().contains("If-Modified-Since: " + formatDate(since)));
10877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
10887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testClientSuppliedConditionWithoutCachedResult() throws Exception {
10907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
10917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
10927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
10937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
10947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection = openConnection(server.getUrl("/"));
10957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        String clientIfModifiedSince = formatDate(-24, TimeUnit.HOURS);
10967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("If-Modified-Since", clientIfModifiedSince);
10977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection.getResponseCode());
10987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("", readAscii(connection));
10997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testAuthorizationRequestHeaderPreventsCaching() throws Exception {
11027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
11037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-2, TimeUnit.MINUTES))
11047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
11057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
11067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
11077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
11087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
11107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(url);
11117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Authorization", "password");
11127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection));
11137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(url)));
11147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testAuthorizationResponseCachedWithSMaxAge() throws Exception {
11177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertAuthorizationRequestFullyCached(new MockResponse()
11187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: s-maxage=60"));
11197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testAuthorizationResponseCachedWithPublic() throws Exception {
11227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertAuthorizationRequestFullyCached(new MockResponse()
11237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: public"));
11247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testAuthorizationResponseCachedWithMustRevalidate() throws Exception {
11277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertAuthorizationRequestFullyCached(new MockResponse()
11287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: must-revalidate"));
11297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void assertAuthorizationRequestFullyCached(MockResponse response) throws Exception {
11327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response
11337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
11347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
11357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
11367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
11377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
11397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(url);
11407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.addRequestProperty("Authorization", "password");
11417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection));
11427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
11437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testContentLocationDoesNotPopulateCache() throws Exception {
11467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
11477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
11487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Content-Location: /bar")
11497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
11507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
11517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
11527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/foo"))));
11547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(server.getUrl("/bar"))));
11557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testUseCachesFalseDoesNotWriteToCache() throws Exception {
11587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
11597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
11607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A").setBody("A"));
11617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
11627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
11637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
11657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.setUseCaches(false);
11667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection));
11677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(server.getUrl("/"))));
11687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testUseCachesFalseDoesNotReadFromCache() throws Exception {
11717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
11727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
11737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A").setBody("A"));
11747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
11757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
11767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
11787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(server.getUrl("/"));
11797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection.setUseCaches(false);
11807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection));
11817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testDefaultUseCachesSetsInitialValueOnly() throws Exception {
11847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = new URL("http://localhost/");
11857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection c1 = openConnection(url);
11867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection c2 = openConnection(url);
11877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertTrue(c1.getDefaultUseCaches());
11887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        c1.setDefaultUseCaches(false);
11897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        try {
11907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertTrue(c1.getUseCaches());
11917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertTrue(c2.getUseCaches());
11927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            URLConnection c3 = openConnection(url);
11937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertFalse(c3.getUseCaches());
11947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } finally {
11957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            c1.setDefaultUseCaches(true);
11967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
11977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
11987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
11997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testConnectionIsReturnedToPoolAfterConditionalSuccess() throws Exception {
12007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
12017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
12027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
12037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
12047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
12057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
12067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
12077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/a"))));
12097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/a"))));
12107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(server.getUrl("/b"))));
12117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, server.takeRequest().getSequenceNumber());
12137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, server.takeRequest().getSequenceNumber());
12147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, server.takeRequest().getSequenceNumber());
12157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
12167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testStatisticsConditionalCacheMiss() throws Exception {
12187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
12197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
12207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
12217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
12227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
12237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("C"));
12247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
12257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
12277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getRequestCount());
12287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getNetworkCount());
12297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getHitCount());
12307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(server.getUrl("/"))));
12317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("C", readAscii(openConnection(server.getUrl("/"))));
12327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(3, cache.getRequestCount());
12337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(3, cache.getNetworkCount());
12347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getHitCount());
12357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
12367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testStatisticsConditionalCacheHit() throws Exception {
12387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
12397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
12407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
12417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
12427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
12437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
12447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
12457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
12477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getRequestCount());
12487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getNetworkCount());
12497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getHitCount());
12507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
12517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
12527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(3, cache.getRequestCount());
12537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(3, cache.getNetworkCount());
12547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, cache.getHitCount());
12557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
12567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testStatisticsFullCacheHit() throws Exception {
12587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
12597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
12607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
12617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
12627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
12647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getRequestCount());
12657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getNetworkCount());
12667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(0, cache.getHitCount());
12677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
12687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
12697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(3, cache.getRequestCount());
12707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(1, cache.getNetworkCount());
12717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, cache.getHitCount());
12727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
12737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMatchesChangedRequestHeaderField() throws Exception {
12757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
12767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
12777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Language")
12787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
12797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
12807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
12817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
12837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection frConnection = openConnection(url);
12847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        frConnection.addRequestProperty("Accept-Language", "fr-CA");
12857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(frConnection));
12867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection enConnection = openConnection(url);
12887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        enConnection.addRequestProperty("Accept-Language", "en-US");
12897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(enConnection));
12907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
12917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
12927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMatchesUnchangedRequestHeaderField() throws Exception {
12937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
12947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
12957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Language")
12967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
12977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
12987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
12997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
13017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(url);
13027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Language", "fr-CA");
13037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
13047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(url);
13057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Language", "fr-CA");
13067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
13077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
13087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMatchesAbsentRequestHeaderField() throws Exception {
13107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
13117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
13127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Foo")
13137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
13147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
13157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
13167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
13187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
13197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
13207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMatchesAddedRequestHeaderField() throws Exception {
13227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
13237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
13247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Foo")
13257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
13267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
13277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
13287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
13307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection fooConnection = openConnection(server.getUrl("/"));
13317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        fooConnection.addRequestProperty("Foo", "bar");
13327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(fooConnection));
13337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
13347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMatchesRemovedRequestHeaderField() throws Exception {
13367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
13377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
13387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Foo")
13397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
13407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
13417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
13427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection fooConnection = openConnection(server.getUrl("/"));
13447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        fooConnection.addRequestProperty("Foo", "bar");
13457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(fooConnection));
13467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(server.getUrl("/"))));
13477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
13487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryFieldsAreCaseInsensitive() throws Exception {
13507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
13517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
13527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: ACCEPT-LANGUAGE")
13537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
13547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
13557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
13567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
13587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(url);
13597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Language", "fr-CA");
13607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
13617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(url);
13627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("accept-language", "fr-CA");
13637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
13647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
13657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMultipleFieldsWithMatch() throws Exception {
13677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
13687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
13697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Language, Accept-Charset")
13707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Encoding")
13717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
13727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
13737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
13747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
13767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(url);
13777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Language", "fr-CA");
13787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Charset", "UTF-8");
13797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Encoding", "identity");
13807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
13817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(url);
13827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Language", "fr-CA");
13837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Charset", "UTF-8");
13847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Encoding", "identity");
13857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
13867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
13877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMultipleFieldsWithNoMatch() throws Exception {
13897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
13907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
13917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Language, Accept-Charset")
13927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Encoding")
13937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
13947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
13957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
13967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
13977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
13987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection frConnection = openConnection(url);
13997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        frConnection.addRequestProperty("Accept-Language", "fr-CA");
14007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        frConnection.addRequestProperty("Accept-Charset", "UTF-8");
14017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        frConnection.addRequestProperty("Accept-Encoding", "identity");
14027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(frConnection));
14037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection enConnection = openConnection(url);
14047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        enConnection.addRequestProperty("Accept-Language", "en-CA");
14057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        enConnection.addRequestProperty("Accept-Charset", "UTF-8");
14067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        enConnection.addRequestProperty("Accept-Encoding", "identity");
14077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(enConnection));
14087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
14097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMultipleFieldValuesWithMatch() throws Exception {
14117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
14127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
14137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Language")
14147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
14157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
14167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
14177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
14197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(url);
14207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR");
14217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Language", "en-US");
14227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
14237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(url);
14257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Language", "fr-CA, fr-FR");
14267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Language", "en-US");
14277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
14287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
14297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryMultipleFieldValuesWithNoMatch() throws Exception {
14317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
14327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
14337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: Accept-Language")
14347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
14357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
14367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
14377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
14397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(url);
14407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Language", "fr-CA, fr-FR");
14417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection1.addRequestProperty("Accept-Language", "en-US");
14427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
14437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(url);
14457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Language", "fr-CA");
14467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        connection2.addRequestProperty("Accept-Language", "en-US");
14477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection2));
14487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
14497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testVaryAsterisk() throws Exception {
14517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
14527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
14537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Vary: *")
14547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
14557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
14567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
14577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(server.getUrl("/"))));
14597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(server.getUrl("/"))));
14607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
14617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
14627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    public void testVaryAndHttps() throws Exception {
14637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        TestSSLContext testSSLContext = TestSSLContext.create();
14647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
14657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse()
14667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Cache-Control: max-age=60")
14677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .addHeader("Vary: Accept-Language")
14687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//                .setBody("A"));
14697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.enqueue(new MockResponse().setBody("B"));
14707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        server.play();
14717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
14727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        URL url = server.getUrl("/");
14737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        HttpsURLConnection connection1 = (HttpsURLConnection) url.openConnection();
14747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection1.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
14757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection1.addRequestProperty("Accept-Language", "en-US");
14767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("A", readAscii(connection1));
14777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
14787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        HttpsURLConnection connection2 = (HttpsURLConnection) url.openConnection();
14797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection2.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
14807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        connection2.addRequestProperty("Accept-Language", "en-US");
14817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        assertEquals("A", readAscii(connection2));
14827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    }
14837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
14847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    public void testDiskWriteFailureCacheDegradation() throws Exception {
14857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        Deque<InvocationHandler> writeHandlers = mockOs.getHandlers("write");
14867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        int i = 0;
14877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        boolean hasMoreScenarios = true;
14887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        while (hasMoreScenarios) {
14897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            mockOs.enqueueNormal("write", i++);
14907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            mockOs.enqueueFault("write");
14917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            exercisePossiblyFaultyCache(false);
14927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            hasMoreScenarios = writeHandlers.isEmpty();
14937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            writeHandlers.clear();
14947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        }
14957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        System.out.println("Exercising the cache performs " + (i - 1) + " writes.");
14967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    }
14977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//
14987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    public void testDiskReadFailureCacheDegradation() throws Exception {
14997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        Deque<InvocationHandler> readHandlers = mockOs.getHandlers("read");
15007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        int i = 0;
15017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        boolean hasMoreScenarios = true;
15027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        while (hasMoreScenarios) {
15037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            mockOs.enqueueNormal("read", i++);
15047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            mockOs.enqueueFault("read");
15057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            exercisePossiblyFaultyCache(true);
15067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            hasMoreScenarios = readHandlers.isEmpty();
15077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//            readHandlers.clear();
15087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        }
15097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//        System.out.println("Exercising the cache performs " + (i - 1) + " reads.");
15107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath//    }
15117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testCachePlusCookies() throws Exception {
15137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Set-Cookie: a=FIRST; domain=" + server.getCookieDomain() + ";")
15157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
15167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
15177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
15187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Set-Cookie: a=SECOND; domain=" + server.getCookieDomain() + ";")
15207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
15217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
15227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
15247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
15257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCookies(url, "a=FIRST");
15267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
15277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertCookies(url, "a=SECOND");
15287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
15297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testGetHeadersReturnsNetworkEndToEndHeaders() throws Exception {
15317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Allow: GET, HEAD")
15337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
15347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
15357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
15367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Allow: GET, HEAD, PUT")
15387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
15397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
15407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(server.getUrl("/"));
15427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
15437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("GET, HEAD", connection1.getHeaderField("Allow"));
15447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(server.getUrl("/"));
15467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
15477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("GET, HEAD, PUT", connection2.getHeaderField("Allow"));
15487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
15497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testGetHeadersReturnsCachedHopByHopHeaders() throws Exception {
15517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Transfer-Encoding: identity")
15537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
15547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
15557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
15567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Transfer-Encoding: none")
15587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
15597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
15607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(server.getUrl("/"));
15627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
15637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("identity", connection1.getHeaderField("Transfer-Encoding"));
15647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(server.getUrl("/"));
15667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
15677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("identity", connection2.getHeaderField("Transfer-Encoding"));
15687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
15697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testGetHeadersDeletesCached100LevelWarnings() throws Exception {
15717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Warning: 199 test danger")
15737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
15747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
15757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
15767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
15787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
15797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(server.getUrl("/"));
15817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
15827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("199 test danger", connection1.getHeaderField("Warning"));
15837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(server.getUrl("/"));
15857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
15867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(null, connection2.getHeaderField("Warning"));
15877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
15887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testGetHeadersRetainsCached200LevelWarnings() throws Exception {
15907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Warning: 299 test danger")
15927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(-1, TimeUnit.HOURS))
15937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
15947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
15957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
15967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
15977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
15987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
15997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection1 = openConnection(server.getUrl("/"));
16007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
16017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("299 test danger", connection1.getHeaderField("Warning"));
16027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection2 = openConnection(server.getUrl("/"));
16047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
16057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("299 test danger", connection2.getHeaderField("Warning"));
16067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void assertCookies(URL url, String... expectedCookies) throws Exception {
16097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> actualCookies = new ArrayList<String>();
16107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        for (HttpCookie cookie : cookieManager.getCookieStore().get(url.toURI())) {
16117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            actualCookies.add(cookie.toString());
16127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
16137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(Arrays.asList(expectedCookies), actualCookies);
16147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testCachePlusRange() throws Exception {
16177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertNotCached(new MockResponse()
16187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_PARTIAL)
16197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Date: " + formatDate(0, TimeUnit.HOURS))
16207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Content-Range: bytes 100-100/200")
16217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60"));
16227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public void testConditionalHitUpdatesCache() throws Exception {
16257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
16267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS))
16277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=0")
16287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
16297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
16307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=30")
16317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Allow: GET, HEAD")
16327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
16337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
16347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
16357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // cache miss; seed the cache
16377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection1 = openConnection(server.getUrl("/a"));
16387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
16397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(null, connection1.getHeaderField("Allow"));
16407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // conditional cache hit; update the cache
16427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection2 = openConnection(server.getUrl("/a"));
16437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode());
16447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
16457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("GET, HEAD", connection2.getHeaderField("Allow"));
16467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // full cache hit
16487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection3 = openConnection(server.getUrl("/a"));
16497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection3));
16507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("GET, HEAD", connection3.getHeaderField("Allow"));
16517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(2, server.getRequestCount());
16537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
16567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * @param delta the offset from the current date to use. Negative
16577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     *     values yield dates in the past; positive values yield dates in the
16587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     *     future.
16597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
16607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private String formatDate(long delta, TimeUnit timeUnit) {
16617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta)));
16627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private String formatDate(Date date) {
16657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
16667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        rfc1123.setTimeZone(TimeZone.getTimeZone("UTC"));
16677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return rfc1123.format(date);
16687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void addRequestBodyIfNecessary(String requestMethod, OkHttpConnection invalidate)
16717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            throws IOException {
16727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        if (requestMethod.equals("POST") || requestMethod.equals("PUT")) {
16737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            invalidate.setDoOutput(true);
16747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            OutputStream requestBody = invalidate.getOutputStream();
16757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            requestBody.write('x');
16767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            requestBody.close();
16777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
16787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void assertNotCached(MockResponse response) throws Exception {
16817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response.setBody("A"));
16827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
16837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
16847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
16867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
16877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(openConnection(url)));
16887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
16897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void exercisePossiblyFaultyCache(boolean permitReadBodyFailures) throws Exception {
16917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.shutdown();
16927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server = new MockWebServer();
16937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse()
16947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .addHeader("Cache-Control: max-age=60")
16957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                .setBody("A"));
16967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setBody("B"));
16977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
16987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
16997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/" + UUID.randomUUID());
17007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
17017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URLConnection connection = openConnection(url);
17037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        InputStream in = connection.getInputStream();
17047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        try {
17057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            int bodyChar = in.read();
17067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertTrue(bodyChar == 'A' || bodyChar == 'B');
17077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            assertEquals(-1, in.read());
17087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } catch (IOException e) {
17097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            if (!permitReadBodyFailures) {
17107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                throw e;
17117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
17127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
17137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
17147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
17167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * @return the request with the conditional get headers.
17177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
17187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private RecordedRequest assertConditionallyCached(MockResponse response) throws Exception {
17197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // scenario 1: condition succeeds
17207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response.setBody("A").setStatus("HTTP/1.1 200 A-OK"));
17217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
17227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        // scenario 2: condition fails
17247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response.setBody("B").setStatus("HTTP/1.1 200 B-OK"));
17257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 C-OK").setBody("C"));
17267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
17287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL valid = server.getUrl("/valid");
17307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection1 = openConnection(valid);
17317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection1));
17327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(HttpURLConnection.HTTP_OK, connection1.getResponseCode());
17337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A-OK", connection1.getResponseMessage());
17347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection2 = openConnection(valid);
17357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(connection2));
17367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode());
17377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A-OK", connection2.getResponseMessage());
17387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL invalid = server.getUrl("/invalid");
17407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection3 = openConnection(invalid);
17417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B", readAscii(connection3));
17427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(HttpURLConnection.HTTP_OK, connection3.getResponseCode());
17437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("B-OK", connection3.getResponseMessage());
17447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection connection4 = openConnection(invalid);
17457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("C", readAscii(connection4));
17467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(HttpURLConnection.HTTP_OK, connection4.getResponseCode());
17477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("C-OK", connection4.getResponseMessage());
17487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.takeRequest(); // regular get
17507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return server.takeRequest(); // conditional get
17517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
17527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void assertFullyCached(MockResponse response) throws Exception {
17547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response.setBody("A"));
17557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.enqueue(response.setBody("B"));
17567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        server.play();
17577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        URL url = server.getUrl("/");
17597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
17607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals("A", readAscii(openConnection(url)));
17617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
17627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
17647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Shortens the body of {@code response} but not the corresponding headers.
17657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Only useful to test how clients respond to the premature conclusion of
17667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * the HTTP body.
17677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
17687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) {
17697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        response.setSocketPolicy(DISCONNECT_AT_END);
17707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        List<String> headers = new ArrayList<String>(response.getHeaders());
17717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep));
17727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        response.getHeaders().clear();
17737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        response.getHeaders().addAll(headers);
17747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return response;
17757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
17767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
17787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Reads {@code count} characters from the stream. If the stream is
17797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * exhausted before {@code count} characters can be read, the remaining
17807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * characters are returned and the stream is closed.
17817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
17827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private String readAscii(URLConnection connection, int count) throws IOException {
17837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OkHttpConnection httpConnection = (OkHttpConnection) connection;
17847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        InputStream in = httpConnection.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST
17857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                ? connection.getInputStream()
17867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                : httpConnection.getErrorStream();
17877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        StringBuilder result = new StringBuilder();
17887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        for (int i = 0; i < count; i++) {
17897899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            int value = in.read();
17907899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            if (value == -1) {
17917899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                in.close();
17927899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                break;
17937899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
17947899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            result.append((char) value);
17957899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
17967899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return result.toString();
17977899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
17987899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
17997899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private String readAscii(URLConnection connection) throws IOException {
18007899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return readAscii(connection, Integer.MAX_VALUE);
18017899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
18027899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18037899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void reliableSkip(InputStream in, int length) throws IOException {
18047899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        while (length > 0) {
18057899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            length -= in.skip(length);
18067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
18077899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
18087899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private void assertGatewayTimeout(OkHttpConnection connection) throws IOException {
18107899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        try {
18117899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            connection.getInputStream();
18127899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            fail();
18137899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        } catch (FileNotFoundException expected) {
18147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
18157899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(504, connection.getResponseCode());
18167899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        assertEquals(-1, connection.getErrorStream().read());
18177899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
18187899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18197899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    enum TransferKind {
18207899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        CHUNKED() {
18217899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            @Override void setBody(MockResponse response, byte[] content, int chunkSize)
18227899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    throws IOException {
18237899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                response.setChunkedBody(content, chunkSize);
18247899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
18257899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        },
18267899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        FIXED_LENGTH() {
18277899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            @Override void setBody(MockResponse response, byte[] content, int chunkSize) {
18287899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                response.setBody(content);
18297899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
18307899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        },
18317899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        END_OF_STREAM() {
18327899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            @Override void setBody(MockResponse response, byte[] content, int chunkSize) {
18337899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                response.setBody(content);
18347899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                response.setSocketPolicy(DISCONNECT_AT_END);
18357899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) {
18367899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    if (h.next().startsWith("Content-Length:")) {
18377899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                        h.remove();
18387899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                        break;
18397899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    }
18407899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                }
18417899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
18427899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        };
18437899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18447899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        abstract void setBody(MockResponse response, byte[] content, int chunkSize)
18457899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                throws IOException;
18467899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18477899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        void setBody(MockResponse response, String content, int chunkSize) throws IOException {
18487899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            setBody(response, content.getBytes("UTF-8"), chunkSize);
18497899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
18507899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
18517899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18527899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private <T> List<T> toListOrNull(T[] arrayOrNull) {
18537899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return arrayOrNull != null ? Arrays.asList(arrayOrNull) : null;
18547899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
18557899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18567899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    /**
18577899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     * Returns a gzipped copy of {@code bytes}.
18587899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath     */
18597899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    public byte[] gzip(byte[] bytes) throws IOException {
18607899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
18617899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        OutputStream gzippedOut = new GZIPOutputStream(bytesOut);
18627899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        gzippedOut.write(bytes);
18637899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        gzippedOut.close();
18647899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        return bytesOut.toByteArray();
18657899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
18667899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18677899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    private class InsecureResponseCache extends ResponseCache {
18687899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException {
18697899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            return cache.put(uri, connection);
18707899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
18717899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
18727899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        @Override public CacheResponse get(URI uri, String requestMethod,
18737899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                Map<String, List<String>> requestHeaders) throws IOException {
18747899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            final CacheResponse response = cache.get(uri, requestMethod, requestHeaders);
18757899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            if (response instanceof SecureCacheResponse) {
18767899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                return new CacheResponse() {
18777899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    @Override public InputStream getBody() throws IOException {
18787899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                        return response.getBody();
18797899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    }
18807899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    @Override public Map<String, List<String>> getHeaders() throws IOException {
18817899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                        return response.getHeaders();
18827899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                    }
18837899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath                };
18847899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            }
18857899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath            return response;
18867899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath        }
18877899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
18887899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath}
1889