Home | History | Annotate | Download | only in okhttp
      1 /*
      2  * Copyright (C) 2013 Square, Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.squareup.okhttp;
     17 
     18 import com.squareup.okhttp.internal.DoubleInetAddressDns;
     19 import com.squareup.okhttp.internal.RecordingOkAuthenticator;
     20 import com.squareup.okhttp.internal.SingleInetAddressDns;
     21 import com.squareup.okhttp.internal.SslContextBuilder;
     22 import com.squareup.okhttp.internal.Util;
     23 import com.squareup.okhttp.internal.Version;
     24 import com.squareup.okhttp.internal.http.FakeDns;
     25 import com.squareup.okhttp.internal.io.InMemoryFileSystem;
     26 import com.squareup.okhttp.mockwebserver.Dispatcher;
     27 import com.squareup.okhttp.mockwebserver.MockResponse;
     28 import com.squareup.okhttp.mockwebserver.MockWebServer;
     29 import com.squareup.okhttp.mockwebserver.RecordedRequest;
     30 import com.squareup.okhttp.mockwebserver.SocketPolicy;
     31 import com.squareup.okhttp.testing.RecordingHostnameVerifier;
     32 import java.io.File;
     33 import java.io.IOException;
     34 import java.io.InputStream;
     35 import java.io.InterruptedIOException;
     36 import java.net.CookieManager;
     37 import java.net.HttpCookie;
     38 import java.net.HttpURLConnection;
     39 import java.net.InetAddress;
     40 import java.net.InetSocketAddress;
     41 import java.net.ProtocolException;
     42 import java.net.ServerSocket;
     43 import java.net.UnknownServiceException;
     44 import java.security.cert.Certificate;
     45 import java.util.ArrayList;
     46 import java.util.Arrays;
     47 import java.util.Collections;
     48 import java.util.List;
     49 import java.util.concurrent.BlockingQueue;
     50 import java.util.concurrent.Callable;
     51 import java.util.concurrent.CountDownLatch;
     52 import java.util.concurrent.ExecutorService;
     53 import java.util.concurrent.Executors;
     54 import java.util.concurrent.Future;
     55 import java.util.concurrent.SynchronousQueue;
     56 import java.util.concurrent.TimeUnit;
     57 import java.util.concurrent.atomic.AtomicBoolean;
     58 import java.util.concurrent.atomic.AtomicReference;
     59 import javax.net.ServerSocketFactory;
     60 import javax.net.ssl.SSLContext;
     61 import javax.net.ssl.SSLHandshakeException;
     62 import javax.net.ssl.SSLPeerUnverifiedException;
     63 import javax.net.ssl.SSLProtocolException;
     64 import javax.net.ssl.SSLSocket;
     65 import javax.net.ssl.SSLSocketFactory;
     66 import okio.Buffer;
     67 import okio.BufferedSink;
     68 import okio.BufferedSource;
     69 import okio.GzipSink;
     70 import okio.Okio;
     71 import org.junit.After;
     72 import org.junit.Before;
     73 import org.junit.Rule;
     74 import org.junit.Test;
     75 import org.junit.rules.TestRule;
     76 import org.junit.rules.Timeout;
     77 
     78 import static com.squareup.okhttp.internal.Internal.logger;
     79 import static java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER;
     80 import static org.junit.Assert.assertEquals;
     81 import static org.junit.Assert.assertFalse;
     82 import static org.junit.Assert.assertNotSame;
     83 import static org.junit.Assert.assertNull;
     84 import static org.junit.Assert.assertTrue;
     85 import static org.junit.Assert.fail;
     86 
     87 public final class CallTest {
     88   @Rule public final TestRule timeout = new Timeout(30_000);
     89   @Rule public final MockWebServer server = new MockWebServer();
     90   @Rule public final MockWebServer server2 = new MockWebServer();
     91   @Rule public final InMemoryFileSystem fileSystem = new InMemoryFileSystem();
     92 
     93   private SSLContext sslContext = SslContextBuilder.localhost();
     94   private OkHttpClient client = new OkHttpClient();
     95   private RecordingCallback callback = new RecordingCallback();
     96   private TestLogHandler logHandler = new TestLogHandler();
     97   private Cache cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem);
     98   private ServerSocket nullServer;
     99 
    100   @Before public void setUp() throws Exception {
    101     logger.addHandler(logHandler);
    102   }
    103 
    104   @After public void tearDown() throws Exception {
    105     cache.delete();
    106     Util.closeQuietly(nullServer);
    107     logger.removeHandler(logHandler);
    108   }
    109 
    110   @Test public void get() throws Exception {
    111     server.enqueue(new MockResponse().setBody("abc").addHeader("Content-Type: text/plain"));
    112 
    113     Request request = new Request.Builder()
    114         .url(server.url("/"))
    115         .header("User-Agent", "SyncApiTest")
    116         .build();
    117 
    118     executeSynchronously(request)
    119         .assertCode(200)
    120         .assertSuccessful()
    121         .assertHeader("Content-Type", "text/plain")
    122         .assertBody("abc");
    123 
    124     RecordedRequest recordedRequest = server.takeRequest();
    125     assertEquals("GET", recordedRequest.getMethod());
    126     assertEquals("SyncApiTest", recordedRequest.getHeader("User-Agent"));
    127     assertEquals(0, recordedRequest.getBody().size());
    128     assertNull(recordedRequest.getHeader("Content-Length"));
    129   }
    130 
    131   @Test public void buildRequestUsingHttpUrl() throws Exception {
    132     server.enqueue(new MockResponse());
    133 
    134     HttpUrl httpUrl = server.url("/");
    135     Request request = new Request.Builder()
    136         .url(httpUrl)
    137         .build();
    138     assertEquals(httpUrl, request.httpUrl());
    139 
    140     executeSynchronously(request).assertSuccessful();
    141   }
    142 
    143   @Test public void invalidScheme() throws Exception {
    144     Request.Builder requestBuilder = new Request.Builder();
    145     try {
    146       requestBuilder.url("ftp://hostname/path");
    147       fail();
    148     } catch (IllegalArgumentException expected) {
    149       assertEquals(expected.getMessage(), "unexpected url: ftp://hostname/path");
    150     }
    151   }
    152 
    153   @Test public void invalidPort() throws Exception {
    154     Request.Builder requestBuilder = new Request.Builder();
    155     try {
    156       requestBuilder.url("http://localhost:65536/");
    157       fail();
    158     } catch (IllegalArgumentException expected) {
    159       assertEquals(expected.getMessage(), "unexpected url: http://localhost:65536/");
    160     }
    161   }
    162 
    163   @Test public void getReturns500() throws Exception {
    164     server.enqueue(new MockResponse().setResponseCode(500));
    165 
    166     Request request = new Request.Builder()
    167         .url(server.url("/"))
    168         .build();
    169 
    170     executeSynchronously(request)
    171         .assertCode(500)
    172         .assertNotSuccessful();
    173   }
    174 
    175   @Test public void get_HTTP_2() throws Exception {
    176     enableProtocol(Protocol.HTTP_2);
    177     get();
    178   }
    179 
    180   @Test public void get_HTTPS() throws Exception {
    181     enableTls();
    182     get();
    183   }
    184 
    185   @Test public void get_SPDY_3() throws Exception {
    186     enableProtocol(Protocol.SPDY_3);
    187     get();
    188   }
    189 
    190   @Test public void repeatedHeaderNames() throws Exception {
    191     server.enqueue(new MockResponse()
    192         .addHeader("B", "123")
    193         .addHeader("B", "234"));
    194 
    195     Request request = new Request.Builder()
    196         .url(server.url("/"))
    197         .addHeader("A", "345")
    198         .addHeader("A", "456")
    199         .build();
    200 
    201     executeSynchronously(request)
    202         .assertCode(200)
    203         .assertHeader("B", "123", "234");
    204 
    205     RecordedRequest recordedRequest = server.takeRequest();
    206     assertEquals(Arrays.asList("345", "456"), recordedRequest.getHeaders().values("A"));
    207   }
    208 
    209   @Test public void repeatedHeaderNames_SPDY_3() throws Exception {
    210     enableProtocol(Protocol.SPDY_3);
    211     repeatedHeaderNames();
    212   }
    213 
    214   @Test public void repeatedHeaderNames_HTTP_2() throws Exception {
    215     enableProtocol(Protocol.HTTP_2);
    216     repeatedHeaderNames();
    217   }
    218 
    219   @Test public void getWithRequestBody() throws Exception {
    220     server.enqueue(new MockResponse());
    221 
    222     try {
    223       new Request.Builder().method("GET", RequestBody.create(MediaType.parse("text/plain"), "abc"));
    224       fail();
    225     } catch (IllegalArgumentException expected) {
    226     }
    227   }
    228 
    229   @Test public void head() throws Exception {
    230     server.enqueue(new MockResponse().addHeader("Content-Type: text/plain"));
    231 
    232     Request request = new Request.Builder()
    233         .url(server.url("/"))
    234         .head()
    235         .header("User-Agent", "SyncApiTest")
    236         .build();
    237 
    238     executeSynchronously(request)
    239         .assertCode(200)
    240         .assertHeader("Content-Type", "text/plain");
    241 
    242     RecordedRequest recordedRequest = server.takeRequest();
    243     assertEquals("HEAD", recordedRequest.getMethod());
    244     assertEquals("SyncApiTest", recordedRequest.getHeader("User-Agent"));
    245     assertEquals(0, recordedRequest.getBody().size());
    246     assertNull(recordedRequest.getHeader("Content-Length"));
    247   }
    248 
    249   @Test public void head_HTTPS() throws Exception {
    250     enableTls();
    251     head();
    252   }
    253 
    254   @Test public void head_HTTP_2() throws Exception {
    255     enableProtocol(Protocol.HTTP_2);
    256     head();
    257   }
    258 
    259   @Test public void head_SPDY_3() throws Exception {
    260     enableProtocol(Protocol.SPDY_3);
    261     head();
    262   }
    263 
    264   @Test public void post() throws Exception {
    265     server.enqueue(new MockResponse().setBody("abc"));
    266 
    267     Request request = new Request.Builder()
    268         .url(server.url("/"))
    269         .post(RequestBody.create(MediaType.parse("text/plain"), "def"))
    270         .build();
    271 
    272     executeSynchronously(request)
    273         .assertCode(200)
    274         .assertBody("abc");
    275 
    276     RecordedRequest recordedRequest = server.takeRequest();
    277     assertEquals("POST", recordedRequest.getMethod());
    278     assertEquals("def", recordedRequest.getBody().readUtf8());
    279     assertEquals("3", recordedRequest.getHeader("Content-Length"));
    280     assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
    281   }
    282 
    283   @Test public void post_HTTPS() throws Exception {
    284     enableTls();
    285     post();
    286   }
    287 
    288   @Test public void post_HTTP_2() throws Exception {
    289     enableProtocol(Protocol.HTTP_2);
    290     post();
    291   }
    292 
    293   @Test public void post_SPDY_3() throws Exception {
    294     enableProtocol(Protocol.SPDY_3);
    295     post();
    296   }
    297 
    298   @Test public void postZeroLength() throws Exception {
    299     server.enqueue(new MockResponse().setBody("abc"));
    300 
    301     Request request = new Request.Builder()
    302         .url(server.url("/"))
    303         .method("POST", RequestBody.create(null, new byte[0]))
    304         .build();
    305 
    306     executeSynchronously(request)
    307         .assertCode(200)
    308         .assertBody("abc");
    309 
    310     RecordedRequest recordedRequest = server.takeRequest();
    311     assertEquals("POST", recordedRequest.getMethod());
    312     assertEquals(0, recordedRequest.getBody().size());
    313     assertEquals("0", recordedRequest.getHeader("Content-Length"));
    314     assertEquals(null, recordedRequest.getHeader("Content-Type"));
    315   }
    316 
    317   @Test public void postZerolength_HTTPS() throws Exception {
    318     enableTls();
    319     postZeroLength();
    320   }
    321 
    322   @Test public void postZerolength_HTTP_2() throws Exception {
    323     enableProtocol(Protocol.HTTP_2);
    324     postZeroLength();
    325   }
    326 
    327   @Test public void postZeroLength_SPDY_3() throws Exception {
    328     enableProtocol(Protocol.SPDY_3);
    329     postZeroLength();
    330   }
    331 
    332   @Test public void postBodyRetransmittedAfterAuthorizationFail() throws Exception {
    333     postBodyRetransmittedAfterAuthorizationFail("abc");
    334   }
    335 
    336   @Test public void postBodyRetransmittedAfterAuthorizationFail_HTTPS() throws Exception {
    337     enableTls();
    338     postBodyRetransmittedAfterAuthorizationFail("abc");
    339   }
    340 
    341   @Test public void postBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception {
    342     enableProtocol(Protocol.HTTP_2);
    343     postBodyRetransmittedAfterAuthorizationFail("abc");
    344   }
    345 
    346   @Test public void postBodyRetransmittedAfterAuthorizationFail_SPDY_3() throws Exception {
    347     enableProtocol(Protocol.SPDY_3);
    348     postBodyRetransmittedAfterAuthorizationFail("abc");
    349   }
    350 
    351   /** Don't explode when resending an empty post. https://github.com/square/okhttp/issues/1131 */
    352   @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail() throws Exception {
    353     postBodyRetransmittedAfterAuthorizationFail("");
    354   }
    355 
    356   @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_HTTPS() throws Exception {
    357     enableTls();
    358     postBodyRetransmittedAfterAuthorizationFail("");
    359   }
    360 
    361   @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception {
    362     enableProtocol(Protocol.HTTP_2);
    363     postBodyRetransmittedAfterAuthorizationFail("");
    364   }
    365 
    366   @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_SPDY_3() throws Exception {
    367     enableProtocol(Protocol.SPDY_3);
    368     postBodyRetransmittedAfterAuthorizationFail("");
    369   }
    370 
    371   private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exception {
    372     server.enqueue(new MockResponse().setResponseCode(401));
    373     server.enqueue(new MockResponse());
    374 
    375     Request request = new Request.Builder()
    376         .url(server.url("/"))
    377         .method("POST", RequestBody.create(null, body))
    378         .build();
    379 
    380     String credential = Credentials.basic("jesse", "secret");
    381     client.setAuthenticator(new RecordingOkAuthenticator(credential));
    382 
    383     Response response = client.newCall(request).execute();
    384     assertEquals(200, response.code());
    385 
    386     RecordedRequest recordedRequest1 = server.takeRequest();
    387     assertEquals("POST", recordedRequest1.getMethod());
    388     assertEquals(body, recordedRequest1.getBody().readUtf8());
    389     assertNull(recordedRequest1.getHeader("Authorization"));
    390 
    391     RecordedRequest recordedRequest2 = server.takeRequest();
    392     assertEquals("POST", recordedRequest2.getMethod());
    393     assertEquals(body, recordedRequest2.getBody().readUtf8());
    394     assertEquals(credential, recordedRequest2.getHeader("Authorization"));
    395   }
    396 
    397   @Test public void attemptAuthorization20Times() throws Exception {
    398     for (int i = 0; i < 20; i++) {
    399       server.enqueue(new MockResponse().setResponseCode(401));
    400     }
    401     server.enqueue(new MockResponse().setBody("Success!"));
    402 
    403     String credential = Credentials.basic("jesse", "secret");
    404     client.setAuthenticator(new RecordingOkAuthenticator(credential));
    405 
    406     Request request = new Request.Builder().url(server.url("/")).build();
    407     executeSynchronously(request)
    408         .assertCode(200)
    409         .assertBody("Success!");
    410   }
    411 
    412   @Test public void doesNotAttemptAuthorization21Times() throws Exception {
    413     for (int i = 0; i < 21; i++) {
    414       server.enqueue(new MockResponse().setResponseCode(401));
    415     }
    416 
    417     String credential = Credentials.basic("jesse", "secret");
    418     client.setAuthenticator(new RecordingOkAuthenticator(credential));
    419 
    420     try {
    421       client.newCall(new Request.Builder().url(server.url("/0")).build()).execute();
    422       fail();
    423     } catch (IOException expected) {
    424       assertEquals("Too many follow-up requests: 21", expected.getMessage());
    425     }
    426   }
    427 
    428   @Test public void delete() throws Exception {
    429     server.enqueue(new MockResponse().setBody("abc"));
    430 
    431     Request request = new Request.Builder()
    432         .url(server.url("/"))
    433         .delete()
    434         .build();
    435 
    436     executeSynchronously(request)
    437         .assertCode(200)
    438         .assertBody("abc");
    439 
    440     RecordedRequest recordedRequest = server.takeRequest();
    441     assertEquals("DELETE", recordedRequest.getMethod());
    442     assertEquals(0, recordedRequest.getBody().size());
    443     assertEquals("0", recordedRequest.getHeader("Content-Length"));
    444     assertEquals(null, recordedRequest.getHeader("Content-Type"));
    445   }
    446 
    447   @Test public void delete_HTTPS() throws Exception {
    448     enableTls();
    449     delete();
    450   }
    451 
    452   @Test public void delete_HTTP_2() throws Exception {
    453     enableProtocol(Protocol.HTTP_2);
    454     delete();
    455   }
    456 
    457   @Test public void delete_SPDY_3() throws Exception {
    458     enableProtocol(Protocol.SPDY_3);
    459     delete();
    460   }
    461 
    462   @Test public void deleteWithRequestBody() throws Exception {
    463     server.enqueue(new MockResponse().setBody("abc"));
    464 
    465     Request request = new Request.Builder()
    466         .url(server.url("/"))
    467         .method("DELETE", RequestBody.create(MediaType.parse("text/plain"), "def"))
    468         .build();
    469 
    470     executeSynchronously(request)
    471         .assertCode(200)
    472         .assertBody("abc");
    473 
    474     RecordedRequest recordedRequest = server.takeRequest();
    475     assertEquals("DELETE", recordedRequest.getMethod());
    476     assertEquals("def", recordedRequest.getBody().readUtf8());
    477   }
    478 
    479   @Test public void put() throws Exception {
    480     server.enqueue(new MockResponse().setBody("abc"));
    481 
    482     Request request = new Request.Builder()
    483         .url(server.url("/"))
    484         .put(RequestBody.create(MediaType.parse("text/plain"), "def"))
    485         .build();
    486 
    487     executeSynchronously(request)
    488         .assertCode(200)
    489         .assertBody("abc");
    490 
    491     RecordedRequest recordedRequest = server.takeRequest();
    492     assertEquals("PUT", recordedRequest.getMethod());
    493     assertEquals("def", recordedRequest.getBody().readUtf8());
    494     assertEquals("3", recordedRequest.getHeader("Content-Length"));
    495     assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
    496   }
    497 
    498   @Test public void put_HTTPS() throws Exception {
    499     enableTls();
    500     put();
    501   }
    502 
    503   @Test public void put_HTTP_2() throws Exception {
    504     enableProtocol(Protocol.HTTP_2);
    505     put();
    506   }
    507 
    508   @Test public void put_SPDY_3() throws Exception {
    509     enableProtocol(Protocol.SPDY_3);
    510     put();
    511   }
    512 
    513   @Test public void patch() throws Exception {
    514     server.enqueue(new MockResponse().setBody("abc"));
    515 
    516     Request request = new Request.Builder()
    517         .url(server.url("/"))
    518         .patch(RequestBody.create(MediaType.parse("text/plain"), "def"))
    519         .build();
    520 
    521     executeSynchronously(request)
    522         .assertCode(200)
    523         .assertBody("abc");
    524 
    525     RecordedRequest recordedRequest = server.takeRequest();
    526     assertEquals("PATCH", recordedRequest.getMethod());
    527     assertEquals("def", recordedRequest.getBody().readUtf8());
    528     assertEquals("3", recordedRequest.getHeader("Content-Length"));
    529     assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
    530   }
    531 
    532   @Test public void patch_HTTP_2() throws Exception {
    533     enableProtocol(Protocol.HTTP_2);
    534     patch();
    535   }
    536 
    537   @Test public void patch_HTTPS() throws Exception {
    538     enableTls();
    539     patch();
    540   }
    541 
    542   @Test public void patch_SPDY_3() throws Exception {
    543     enableProtocol(Protocol.SPDY_3);
    544     patch();
    545   }
    546 
    547   @Test public void unspecifiedRequestBodyContentTypeDoesNotGetDefault() throws Exception {
    548     server.enqueue(new MockResponse());
    549 
    550     Request request = new Request.Builder()
    551         .url(server.url("/"))
    552         .method("POST", RequestBody.create(null, "abc"))
    553         .build();
    554 
    555     executeSynchronously(request).assertCode(200);
    556 
    557     RecordedRequest recordedRequest = server.takeRequest();
    558     assertEquals(null, recordedRequest.getHeader("Content-Type"));
    559     assertEquals("3", recordedRequest.getHeader("Content-Length"));
    560     assertEquals("abc", recordedRequest.getBody().readUtf8());
    561   }
    562 
    563   @Test public void illegalToExecuteTwice() throws Exception {
    564     server.enqueue(new MockResponse()
    565         .setBody("abc")
    566         .addHeader("Content-Type: text/plain"));
    567 
    568     Request request = new Request.Builder()
    569         .url(server.url("/"))
    570         .header("User-Agent", "SyncApiTest")
    571         .build();
    572 
    573     Call call = client.newCall(request);
    574     Response response = call.execute();
    575     response.body().close();
    576 
    577     try {
    578       call.execute();
    579       fail();
    580     } catch (IllegalStateException e){
    581       assertEquals("Already Executed", e.getMessage());
    582     }
    583 
    584     try {
    585       call.enqueue(callback);
    586       fail();
    587     } catch (IllegalStateException e){
    588       assertEquals("Already Executed", e.getMessage());
    589     }
    590 
    591     assertEquals("SyncApiTest", server.takeRequest().getHeader("User-Agent"));
    592   }
    593 
    594   @Test public void illegalToExecuteTwice_Async() throws Exception {
    595     server.enqueue(new MockResponse()
    596         .setBody("abc")
    597         .addHeader("Content-Type: text/plain"));
    598 
    599     Request request = new Request.Builder()
    600         .url(server.url("/"))
    601         .header("User-Agent", "SyncApiTest")
    602         .build();
    603 
    604     Call call = client.newCall(request);
    605     call.enqueue(callback);
    606 
    607     try {
    608       call.execute();
    609       fail();
    610     } catch (IllegalStateException e){
    611       assertEquals("Already Executed", e.getMessage());
    612     }
    613 
    614     try {
    615       call.enqueue(callback);
    616       fail();
    617     } catch (IllegalStateException e){
    618       assertEquals("Already Executed", e.getMessage());
    619     }
    620 
    621     assertEquals("SyncApiTest", server.takeRequest().getHeader("User-Agent"));
    622   }
    623 
    624   @Test public void get_Async() throws Exception {
    625     server.enqueue(new MockResponse()
    626         .setBody("abc")
    627         .addHeader("Content-Type: text/plain"));
    628 
    629     Request request = new Request.Builder()
    630         .url(server.url("/"))
    631         .header("User-Agent", "AsyncApiTest")
    632         .build();
    633     client.newCall(request).enqueue(callback);
    634 
    635     callback.await(request.httpUrl())
    636         .assertCode(200)
    637         .assertHeader("Content-Type", "text/plain")
    638         .assertBody("abc");
    639 
    640     assertEquals("AsyncApiTest", server.takeRequest().getHeader("User-Agent"));
    641   }
    642 
    643   @Test public void exceptionThrownByOnResponseIsRedactedAndLogged() throws Exception {
    644     server.enqueue(new MockResponse());
    645 
    646     Request request = new Request.Builder()
    647         .url(server.url("/secret"))
    648         .build();
    649 
    650     client.newCall(request).enqueue(new Callback() {
    651       @Override public void onFailure(Request request, IOException e) {
    652         fail();
    653       }
    654 
    655       @Override public void onResponse(Response response) throws IOException {
    656         throw new IOException("a");
    657       }
    658     });
    659 
    660     assertEquals("INFO: Callback failure for call to " + server.url("/") + "...",
    661         logHandler.take());
    662   }
    663 
    664   @Test public void connectionPooling() throws Exception {
    665     server.enqueue(new MockResponse().setBody("abc"));
    666     server.enqueue(new MockResponse().setBody("def"));
    667     server.enqueue(new MockResponse().setBody("ghi"));
    668 
    669     executeSynchronously(new Request.Builder().url(server.url("/a")).build())
    670         .assertBody("abc");
    671 
    672     executeSynchronously(new Request.Builder().url(server.url("/b")).build())
    673         .assertBody("def");
    674 
    675     executeSynchronously(new Request.Builder().url(server.url("/c")).build())
    676         .assertBody("ghi");
    677 
    678     assertEquals(0, server.takeRequest().getSequenceNumber());
    679     assertEquals(1, server.takeRequest().getSequenceNumber());
    680     assertEquals(2, server.takeRequest().getSequenceNumber());
    681   }
    682 
    683   @Test public void connectionPooling_Async() throws Exception {
    684     server.enqueue(new MockResponse().setBody("abc"));
    685     server.enqueue(new MockResponse().setBody("def"));
    686     server.enqueue(new MockResponse().setBody("ghi"));
    687 
    688     client.newCall(new Request.Builder().url(server.url("/a")).build()).enqueue(callback);
    689     callback.await(server.url("/a")).assertBody("abc");
    690 
    691     client.newCall(new Request.Builder().url(server.url("/b")).build()).enqueue(callback);
    692     callback.await(server.url("/b")).assertBody("def");
    693 
    694     client.newCall(new Request.Builder().url(server.url("/c")).build()).enqueue(callback);
    695     callback.await(server.url("/c")).assertBody("ghi");
    696 
    697     assertEquals(0, server.takeRequest().getSequenceNumber());
    698     assertEquals(1, server.takeRequest().getSequenceNumber());
    699     assertEquals(2, server.takeRequest().getSequenceNumber());
    700   }
    701 
    702   @Test public void connectionReuseWhenResponseBodyConsumed_Async() throws Exception {
    703     server.enqueue(new MockResponse().setBody("abc"));
    704     server.enqueue(new MockResponse().setBody("def"));
    705 
    706     Request request = new Request.Builder().url(server.url("/a")).build();
    707     client.newCall(request).enqueue(new Callback() {
    708       @Override public void onFailure(Request request, IOException e) {
    709         throw new AssertionError();
    710       }
    711 
    712       @Override public void onResponse(Response response) throws IOException {
    713         InputStream bytes = response.body().byteStream();
    714         assertEquals('a', bytes.read());
    715         assertEquals('b', bytes.read());
    716         assertEquals('c', bytes.read());
    717 
    718         // This request will share a connection with 'A' cause it's all done.
    719         client.newCall(new Request.Builder().url(server.url("/b")).build()).enqueue(callback);
    720       }
    721     });
    722 
    723     callback.await(server.url("/b")).assertCode(200).assertBody("def");
    724     assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection.
    725     assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reuse!
    726   }
    727 
    728   @Test public void timeoutsUpdatedOnReusedConnections() throws Exception {
    729     server.enqueue(new MockResponse().setBody("abc"));
    730     server.enqueue(new MockResponse().setBody("def").throttleBody(1, 750, TimeUnit.MILLISECONDS));
    731 
    732     // First request: time out after 1000ms.
    733     client.setReadTimeout(1000, TimeUnit.MILLISECONDS);
    734     executeSynchronously(new Request.Builder().url(server.url("/a")).build()).assertBody("abc");
    735 
    736     // Second request: time out after 250ms.
    737     client.setReadTimeout(250, TimeUnit.MILLISECONDS);
    738     Request request = new Request.Builder().url(server.url("/b")).build();
    739     Response response = client.newCall(request).execute();
    740     BufferedSource bodySource = response.body().source();
    741     assertEquals('d', bodySource.readByte());
    742 
    743     // The second byte of this request will be delayed by 750ms so we should time out after 250ms.
    744     long startNanos = System.nanoTime();
    745     try {
    746       bodySource.readByte();
    747       fail();
    748     } catch (IOException expected) {
    749       // Timed out as expected.
    750       long elapsedNanos = System.nanoTime() - startNanos;
    751       long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(elapsedNanos);
    752       assertTrue(String.format("Timed out: %sms", elapsedMillis), elapsedMillis < 500);
    753     } finally {
    754       bodySource.close();
    755     }
    756   }
    757 
    758   /** https://github.com/square/okhttp/issues/442 */
    759   @Test public void timeoutsNotRetried() throws Exception {
    760     server.enqueue(new MockResponse()
    761         .setSocketPolicy(SocketPolicy.NO_RESPONSE));
    762     server.enqueue(new MockResponse()
    763         .setBody("unreachable!"));
    764 
    765     client.setDns(new DoubleInetAddressDns());
    766     client.setReadTimeout(100, TimeUnit.MILLISECONDS);
    767 
    768     Request request = new Request.Builder().url(server.url("/")).build();
    769     try {
    770       // If this succeeds, too many requests were made.
    771       client.newCall(request).execute();
    772       fail();
    773     } catch (InterruptedIOException expected) {
    774     }
    775   }
    776 
    777   /** https://github.com/square/okhttp/issues/1801 */
    778   @Test public void asyncCallEngineInitialized() throws Exception {
    779     OkHttpClient c = new OkHttpClient();
    780     c.interceptors().add(new Interceptor() {
    781       @Override public Response intercept(Chain chain) throws IOException {
    782         throw new IOException();
    783       }
    784     });
    785     Request request = new Request.Builder().url(server.url("/")).build();
    786     c.newCall(request).enqueue(callback);
    787     RecordedResponse response = callback.await(request.httpUrl());
    788     assertEquals(request, response.request);
    789   }
    790 
    791   @Test public void reusedSinksGetIndependentTimeoutInstances() throws Exception {
    792     server.enqueue(new MockResponse());
    793     server.enqueue(new MockResponse());
    794 
    795     // Call 1: set a deadline on the request body.
    796     RequestBody requestBody1 = new RequestBody() {
    797       @Override public MediaType contentType() {
    798         return MediaType.parse("text/plain");
    799       }
    800       @Override public void writeTo(BufferedSink sink) throws IOException {
    801         sink.writeUtf8("abc");
    802         sink.timeout().deadline(5, TimeUnit.SECONDS);
    803       }
    804     };
    805     Request request1 = new Request.Builder()
    806         .url(server.url("/"))
    807         .method("POST", requestBody1)
    808         .build();
    809     Response response1 = client.newCall(request1).execute();
    810     assertEquals(200, response1.code());
    811 
    812     // Call 2: check for the absence of a deadline on the request body.
    813     RequestBody requestBody2 = new RequestBody() {
    814       @Override public MediaType contentType() {
    815         return MediaType.parse("text/plain");
    816       }
    817       @Override public void writeTo(BufferedSink sink) throws IOException {
    818         assertFalse(sink.timeout().hasDeadline());
    819         sink.writeUtf8("def");
    820       }
    821     };
    822     Request request2 = new Request.Builder()
    823         .url(server.url("/"))
    824         .method("POST", requestBody2)
    825         .build();
    826     Response response2 = client.newCall(request2).execute();
    827     assertEquals(200, response2.code());
    828 
    829     // Use sequence numbers to confirm the connection was pooled.
    830     assertEquals(0, server.takeRequest().getSequenceNumber());
    831     assertEquals(1, server.takeRequest().getSequenceNumber());
    832   }
    833 
    834   @Test public void reusedSourcesGetIndependentTimeoutInstances() throws Exception {
    835     server.enqueue(new MockResponse().setBody("abc"));
    836     server.enqueue(new MockResponse().setBody("def"));
    837 
    838     // Call 1: set a deadline on the response body.
    839     Request request1 = new Request.Builder().url(server.url("/")).build();
    840     Response response1 = client.newCall(request1).execute();
    841     BufferedSource body1 = response1.body().source();
    842     assertEquals("abc", body1.readUtf8());
    843     body1.timeout().deadline(5, TimeUnit.SECONDS);
    844 
    845     // Call 2: check for the absence of a deadline on the request body.
    846     Request request2 = new Request.Builder().url(server.url("/")).build();
    847     Response response2 = client.newCall(request2).execute();
    848     BufferedSource body2 = response2.body().source();
    849     assertEquals("def", body2.readUtf8());
    850     assertFalse(body2.timeout().hasDeadline());
    851 
    852     // Use sequence numbers to confirm the connection was pooled.
    853     assertEquals(0, server.takeRequest().getSequenceNumber());
    854     assertEquals(1, server.takeRequest().getSequenceNumber());
    855   }
    856 
    857   @Test public void tls() throws Exception {
    858     enableTls();
    859     server.enqueue(new MockResponse()
    860         .setBody("abc")
    861         .addHeader("Content-Type: text/plain"));
    862 
    863     executeSynchronously(new Request.Builder().url(server.url("/")).build())
    864         .assertHandshake();
    865   }
    866 
    867   @Test public void tls_Async() throws Exception {
    868     enableTls();
    869     server.enqueue(new MockResponse()
    870         .setBody("abc")
    871         .addHeader("Content-Type: text/plain"));
    872 
    873     Request request = new Request.Builder()
    874         .url(server.url("/"))
    875         .build();
    876     client.newCall(request).enqueue(callback);
    877 
    878     callback.await(request.httpUrl()).assertHandshake();
    879   }
    880 
    881   @Test public void recoverWhenRetryOnConnectionFailureIsTrue() throws Exception {
    882     server.enqueue(new MockResponse().setBody("seed connection pool"));
    883     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST));
    884     server.enqueue(new MockResponse().setBody("retry success"));
    885 
    886     client.setDns(new DoubleInetAddressDns());
    887     assertTrue(client.getRetryOnConnectionFailure());
    888 
    889     Request request = new Request.Builder().url(server.url("/")).build();
    890     executeSynchronously(request).assertBody("seed connection pool");
    891     executeSynchronously(request).assertBody("retry success");
    892   }
    893 
    894   @Test public void noRecoverWhenRetryOnConnectionFailureIsFalse() throws Exception {
    895     server.enqueue(new MockResponse().setBody("seed connection pool"));
    896     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST));
    897     server.enqueue(new MockResponse().setBody("unreachable!"));
    898 
    899     client.setDns(new DoubleInetAddressDns());
    900     client.setRetryOnConnectionFailure(false);
    901 
    902     Request request = new Request.Builder().url(server.url("/")).build();
    903     executeSynchronously(request).assertBody("seed connection pool");
    904     try {
    905       // If this succeeds, too many requests were made.
    906       client.newCall(request).execute();
    907       fail();
    908     } catch (IOException expected) {
    909     }
    910   }
    911 
    912   @Test public void recoverFromTlsHandshakeFailure() throws Exception {
    913     server.useHttps(sslContext.getSocketFactory(), false);
    914     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
    915     server.enqueue(new MockResponse().setBody("abc"));
    916 
    917     suppressTlsFallbackScsv(client);
    918     client.setHostnameVerifier(new RecordingHostnameVerifier());
    919     client.setDns(new SingleInetAddressDns());
    920 
    921     executeSynchronously(new Request.Builder().url(server.url("/")).build())
    922         .assertBody("abc");
    923   }
    924 
    925   @Test public void recoverFromTlsHandshakeFailure_tlsFallbackScsvEnabled() throws Exception {
    926     final String tlsFallbackScsv = "TLS_FALLBACK_SCSV";
    927     List<String> supportedCiphers =
    928         Arrays.asList(sslContext.getSocketFactory().getSupportedCipherSuites());
    929     if (!supportedCiphers.contains(tlsFallbackScsv)) {
    930       // This only works if the client socket supports TLS_FALLBACK_SCSV.
    931       return;
    932     }
    933 
    934     server.useHttps(sslContext.getSocketFactory(), false);
    935     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
    936 
    937     RecordingSSLSocketFactory clientSocketFactory =
    938         new RecordingSSLSocketFactory(sslContext.getSocketFactory());
    939     client.setSslSocketFactory(clientSocketFactory);
    940     client.setHostnameVerifier(new RecordingHostnameVerifier());
    941     client.setDns(new SingleInetAddressDns());
    942 
    943     Request request = new Request.Builder().url(server.url("/")).build();
    944     try {
    945       client.newCall(request).execute();
    946       fail();
    947     } catch (SSLHandshakeException expected) {
    948     }
    949 
    950     List<SSLSocket> clientSockets = clientSocketFactory.getSocketsCreated();
    951     SSLSocket firstSocket = clientSockets.get(0);
    952     assertFalse(Arrays.asList(firstSocket.getEnabledCipherSuites()).contains(tlsFallbackScsv));
    953     SSLSocket secondSocket = clientSockets.get(1);
    954     assertTrue(Arrays.asList(secondSocket.getEnabledCipherSuites()).contains(tlsFallbackScsv));
    955   }
    956 
    957   @Test public void recoverFromTlsHandshakeFailure_Async() throws Exception {
    958     server.useHttps(sslContext.getSocketFactory(), false);
    959     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
    960     server.enqueue(new MockResponse().setBody("abc"));
    961 
    962     suppressTlsFallbackScsv(client);
    963     client.setHostnameVerifier(new RecordingHostnameVerifier());
    964 
    965     Request request = new Request.Builder()
    966         .url(server.url("/"))
    967         .build();
    968     client.newCall(request).enqueue(callback);
    969 
    970     callback.await(request.httpUrl()).assertBody("abc");
    971   }
    972 
    973   @Test public void noRecoveryFromTlsHandshakeFailureWhenTlsFallbackIsDisabled() throws Exception {
    974     client.setConnectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT));
    975 
    976     server.useHttps(sslContext.getSocketFactory(), false);
    977     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
    978 
    979     suppressTlsFallbackScsv(client);
    980     client.setHostnameVerifier(new RecordingHostnameVerifier());
    981     client.setDns(new SingleInetAddressDns());
    982 
    983     Request request = new Request.Builder().url(server.url("/")).build();
    984     try {
    985       client.newCall(request).execute();
    986       fail();
    987     } catch (SSLProtocolException expected) {
    988       // RI response to the FAIL_HANDSHAKE
    989     } catch (SSLHandshakeException expected) {
    990       // Android's response to the FAIL_HANDSHAKE
    991     }
    992   }
    993 
    994   @Test public void cleartextCallsFailWhenCleartextIsDisabled() throws Exception {
    995     // Configure the client with only TLS configurations. No cleartext!
    996     client.setConnectionSpecs(
    997         Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS));
    998 
    999     server.enqueue(new MockResponse());
   1000 
   1001     Request request = new Request.Builder().url(server.url("/")).build();
   1002     try {
   1003       client.newCall(request).execute();
   1004       fail();
   1005     } catch (UnknownServiceException expected) {
   1006       assertTrue(expected.getMessage().contains("CLEARTEXT communication not supported"));
   1007     }
   1008   }
   1009 
   1010   @Test public void setFollowSslRedirectsFalse() throws Exception {
   1011     enableTls();
   1012     server.enqueue(new MockResponse()
   1013         .setResponseCode(301)
   1014         .addHeader("Location: http://square.com"));
   1015 
   1016     client.setFollowSslRedirects(false);
   1017 
   1018     Request request = new Request.Builder().url(server.url("/")).build();
   1019     Response response = client.newCall(request).execute();
   1020     assertEquals(301, response.code());
   1021     response.body().close();
   1022   }
   1023 
   1024   @Test public void matchingPinnedCertificate() throws Exception {
   1025     enableTls();
   1026     server.enqueue(new MockResponse());
   1027     server.enqueue(new MockResponse());
   1028 
   1029     // Make a first request without certificate pinning. Use it to collect certificates to pin.
   1030     Request request1 = new Request.Builder().url(server.url("/")).build();
   1031     Response response1 = client.newCall(request1).execute();
   1032     CertificatePinner.Builder certificatePinnerBuilder = new CertificatePinner.Builder();
   1033     for (Certificate certificate : response1.handshake().peerCertificates()) {
   1034       certificatePinnerBuilder.add(server.getHostName(), CertificatePinner.pin(certificate));
   1035     }
   1036     response1.body().close();
   1037 
   1038     // Make another request with certificate pinning. It should complete normally.
   1039     client.setCertificatePinner(certificatePinnerBuilder.build());
   1040     Request request2 = new Request.Builder().url(server.url("/")).build();
   1041     Response response2 = client.newCall(request2).execute();
   1042     assertNotSame(response2.handshake(), response1.handshake());
   1043     response2.body().close();
   1044   }
   1045 
   1046   @Test public void unmatchingPinnedCertificate() throws Exception {
   1047     enableTls();
   1048     server.enqueue(new MockResponse());
   1049 
   1050     // Pin publicobject.com's cert.
   1051     client.setCertificatePinner(new CertificatePinner.Builder()
   1052         .add(server.getHostName(), "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
   1053         .build());
   1054 
   1055     // When we pin the wrong certificate, connectivity fails.
   1056     Request request = new Request.Builder().url(server.url("/")).build();
   1057     try {
   1058       client.newCall(request).execute();
   1059       fail();
   1060     } catch (SSLPeerUnverifiedException expected) {
   1061       assertTrue(expected.getMessage().startsWith("Certificate pinning failure!"));
   1062     }
   1063   }
   1064 
   1065   @Test public void post_Async() throws Exception {
   1066     server.enqueue(new MockResponse().setBody("abc"));
   1067 
   1068     Request request = new Request.Builder()
   1069         .url(server.url("/"))
   1070         .post(RequestBody.create(MediaType.parse("text/plain"), "def"))
   1071         .build();
   1072     client.newCall(request).enqueue(callback);
   1073 
   1074     callback.await(request.httpUrl())
   1075         .assertCode(200)
   1076         .assertBody("abc");
   1077 
   1078     RecordedRequest recordedRequest = server.takeRequest();
   1079     assertEquals("def", recordedRequest.getBody().readUtf8());
   1080     assertEquals("3", recordedRequest.getHeader("Content-Length"));
   1081     assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
   1082   }
   1083 
   1084   @Test public void postBodyRetransmittedOnFailureRecovery() throws Exception {
   1085     server.enqueue(new MockResponse().setBody("abc"));
   1086     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST));
   1087     server.enqueue(new MockResponse().setBody("def"));
   1088 
   1089     // Seed the connection pool so we have something that can fail.
   1090     Request request1 = new Request.Builder().url(server.url("/")).build();
   1091     Response response1 = client.newCall(request1).execute();
   1092     assertEquals("abc", response1.body().string());
   1093 
   1094     Request request2 = new Request.Builder()
   1095         .url(server.url("/"))
   1096         .post(RequestBody.create(MediaType.parse("text/plain"), "body!"))
   1097         .build();
   1098     Response response2 = client.newCall(request2).execute();
   1099     assertEquals("def", response2.body().string());
   1100 
   1101     RecordedRequest get = server.takeRequest();
   1102     assertEquals(0, get.getSequenceNumber());
   1103 
   1104     RecordedRequest post1 = server.takeRequest();
   1105     assertEquals("body!", post1.getBody().readUtf8());
   1106     assertEquals(1, post1.getSequenceNumber());
   1107 
   1108     RecordedRequest post2 = server.takeRequest();
   1109     assertEquals("body!", post2.getBody().readUtf8());
   1110     assertEquals(0, post2.getSequenceNumber());
   1111   }
   1112 
   1113   @Test public void cacheHit() throws Exception {
   1114     server.enqueue(new MockResponse()
   1115         .addHeader("ETag: v1")
   1116         .addHeader("Cache-Control: max-age=60")
   1117         .addHeader("Vary: Accept-Charset")
   1118         .setBody("A"));
   1119 
   1120     client.setCache(cache);
   1121 
   1122     // Store a response in the cache.
   1123     HttpUrl url = server.url("/");
   1124     Request cacheStoreRequest = new Request.Builder()
   1125         .url(url)
   1126         .addHeader("Accept-Language", "fr-CA")
   1127         .addHeader("Accept-Charset", "UTF-8")
   1128         .build();
   1129     executeSynchronously(cacheStoreRequest)
   1130         .assertCode(200)
   1131         .assertBody("A");
   1132     assertNull(server.takeRequest().getHeader("If-None-Match"));
   1133 
   1134     // Hit that stored response.
   1135     Request cacheHitRequest = new Request.Builder()
   1136         .url(url)
   1137         .addHeader("Accept-Language", "en-US") // Different, but Vary says it doesn't matter.
   1138         .addHeader("Accept-Charset", "UTF-8")
   1139         .build();
   1140     RecordedResponse cacheHit = executeSynchronously(cacheHitRequest);
   1141 
   1142     // Check the merged response. The request is the application's original request.
   1143     cacheHit.assertCode(200)
   1144         .assertBody("A")
   1145         .assertHeader("ETag", "v1")
   1146         .assertRequestUrl(cacheStoreRequest.url())
   1147         .assertRequestHeader("Accept-Language", "en-US")
   1148         .assertRequestHeader("Accept-Charset", "UTF-8");
   1149 
   1150     // Check the cached response. Its request contains only the saved Vary headers.
   1151     cacheHit.cacheResponse()
   1152         .assertCode(200)
   1153         .assertHeader("ETag", "v1")
   1154         .assertRequestMethod("GET")
   1155         .assertRequestUrl(cacheStoreRequest.url())
   1156         .assertRequestHeader("Accept-Language")
   1157         .assertRequestHeader("Accept-Charset", "UTF-8");
   1158 
   1159     cacheHit.assertNoNetworkResponse();
   1160   }
   1161 
   1162   @Test public void conditionalCacheHit() throws Exception {
   1163     server.enqueue(new MockResponse()
   1164         .addHeader("ETag: v1")
   1165         .addHeader("Vary: Accept-Charset")
   1166         .addHeader("Donut: a")
   1167         .setBody("A"));
   1168     server.enqueue(new MockResponse().clearHeaders()
   1169         .addHeader("Donut: b")
   1170         .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
   1171 
   1172     client.setCache(cache);
   1173 
   1174     // Store a response in the cache.
   1175     HttpUrl url = server.url("/");
   1176     Request cacheStoreRequest = new Request.Builder()
   1177         .url(url)
   1178         .addHeader("Accept-Language", "fr-CA")
   1179         .addHeader("Accept-Charset", "UTF-8")
   1180         .build();
   1181     executeSynchronously(cacheStoreRequest)
   1182         .assertCode(200)
   1183         .assertHeader("Donut", "a")
   1184         .assertBody("A");
   1185     assertNull(server.takeRequest().getHeader("If-None-Match"));
   1186 
   1187     // Hit that stored response.
   1188     Request cacheHitRequest = new Request.Builder()
   1189         .url(url)
   1190         .addHeader("Accept-Language", "en-US") // Different, but Vary says it doesn't matter.
   1191         .addHeader("Accept-Charset", "UTF-8")
   1192         .build();
   1193     RecordedResponse cacheHit = executeSynchronously(cacheHitRequest);
   1194     assertEquals("v1", server.takeRequest().getHeader("If-None-Match"));
   1195 
   1196     // Check the merged response. The request is the application's original request.
   1197     cacheHit.assertCode(200)
   1198         .assertBody("A")
   1199         .assertHeader("Donut", "b")
   1200         .assertRequestUrl(cacheStoreRequest.url())
   1201         .assertRequestHeader("Accept-Language", "en-US")
   1202         .assertRequestHeader("Accept-Charset", "UTF-8")
   1203         .assertRequestHeader("If-None-Match"); // No If-None-Match on the user's request.
   1204 
   1205     // Check the cached response. Its request contains only the saved Vary headers.
   1206     cacheHit.cacheResponse()
   1207         .assertCode(200)
   1208         .assertHeader("Donut", "a")
   1209         .assertHeader("ETag", "v1")
   1210         .assertRequestUrl(cacheStoreRequest.url())
   1211         .assertRequestHeader("Accept-Language") // No Vary on Accept-Language.
   1212         .assertRequestHeader("Accept-Charset", "UTF-8") // Because of Vary on Accept-Charset.
   1213         .assertRequestHeader("If-None-Match"); // This wasn't present in the original request.
   1214 
   1215     // Check the network response. It has the caller's request, plus some caching headers.
   1216     cacheHit.networkResponse()
   1217         .assertCode(304)
   1218         .assertHeader("Donut", "b")
   1219         .assertRequestHeader("Accept-Language", "en-US")
   1220         .assertRequestHeader("Accept-Charset", "UTF-8")
   1221         .assertRequestHeader("If-None-Match", "v1"); // If-None-Match in the validation request.
   1222   }
   1223 
   1224   @Test public void conditionalCacheHit_Async() throws Exception {
   1225     server.enqueue(new MockResponse().setBody("A").addHeader("ETag: v1"));
   1226     server.enqueue(new MockResponse()
   1227         .clearHeaders()
   1228         .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
   1229 
   1230     client.setCache(cache);
   1231 
   1232     Request request1 = new Request.Builder()
   1233         .url(server.url("/"))
   1234         .build();
   1235     client.newCall(request1).enqueue(callback);
   1236     callback.await(request1.httpUrl()).assertCode(200).assertBody("A");
   1237     assertNull(server.takeRequest().getHeader("If-None-Match"));
   1238 
   1239     Request request2 = new Request.Builder()
   1240         .url(server.url("/"))
   1241         .build();
   1242     client.newCall(request2).enqueue(callback);
   1243     callback.await(request2.httpUrl()).assertCode(200).assertBody("A");
   1244     assertEquals("v1", server.takeRequest().getHeader("If-None-Match"));
   1245   }
   1246 
   1247   @Test public void conditionalCacheMiss() throws Exception {
   1248     server.enqueue(new MockResponse()
   1249         .addHeader("ETag: v1")
   1250         .addHeader("Vary: Accept-Charset")
   1251         .addHeader("Donut: a")
   1252         .setBody("A"));
   1253     server.enqueue(new MockResponse()
   1254         .addHeader("Donut: b")
   1255         .setBody("B"));
   1256 
   1257     client.setCache(cache);
   1258 
   1259     Request cacheStoreRequest = new Request.Builder()
   1260         .url(server.url("/"))
   1261         .addHeader("Accept-Language", "fr-CA")
   1262         .addHeader("Accept-Charset", "UTF-8")
   1263         .build();
   1264     executeSynchronously(cacheStoreRequest)
   1265         .assertCode(200)
   1266         .assertBody("A");
   1267     assertNull(server.takeRequest().getHeader("If-None-Match"));
   1268 
   1269     Request cacheMissRequest = new Request.Builder()
   1270         .url(server.url("/"))
   1271         .addHeader("Accept-Language", "en-US") // Different, but Vary says it doesn't matter.
   1272         .addHeader("Accept-Charset", "UTF-8")
   1273         .build();
   1274     RecordedResponse cacheHit = executeSynchronously(cacheMissRequest);
   1275     assertEquals("v1", server.takeRequest().getHeader("If-None-Match"));
   1276 
   1277     // Check the user response. It has the application's original request.
   1278     cacheHit.assertCode(200)
   1279         .assertBody("B")
   1280         .assertHeader("Donut", "b")
   1281         .assertRequestUrl(cacheStoreRequest.url());
   1282 
   1283     // Check the cache response. Even though it's a miss, we used the cache.
   1284     cacheHit.cacheResponse()
   1285         .assertCode(200)
   1286         .assertHeader("Donut", "a")
   1287         .assertHeader("ETag", "v1")
   1288         .assertRequestUrl(cacheStoreRequest.url());
   1289 
   1290     // Check the network response. It has the network request, plus caching headers.
   1291     cacheHit.networkResponse()
   1292         .assertCode(200)
   1293         .assertHeader("Donut", "b")
   1294         .assertRequestHeader("If-None-Match", "v1")  // If-None-Match in the validation request.
   1295         .assertRequestUrl(cacheStoreRequest.url());
   1296   }
   1297 
   1298   @Test public void conditionalCacheMiss_Async() throws Exception {
   1299     server.enqueue(new MockResponse().setBody("A").addHeader("ETag: v1"));
   1300     server.enqueue(new MockResponse().setBody("B"));
   1301 
   1302     client.setCache(cache);
   1303 
   1304     Request request1 = new Request.Builder()
   1305         .url(server.url("/"))
   1306         .build();
   1307     client.newCall(request1).enqueue(callback);
   1308     callback.await(request1.httpUrl()).assertCode(200).assertBody("A");
   1309     assertNull(server.takeRequest().getHeader("If-None-Match"));
   1310 
   1311     Request request2 = new Request.Builder()
   1312         .url(server.url("/"))
   1313         .build();
   1314     client.newCall(request2).enqueue(callback);
   1315     callback.await(request2.httpUrl()).assertCode(200).assertBody("B");
   1316     assertEquals("v1", server.takeRequest().getHeader("If-None-Match"));
   1317   }
   1318 
   1319   @Test public void onlyIfCachedReturns504WhenNotCached() throws Exception {
   1320     Request request = new Request.Builder()
   1321         .url(server.url("/"))
   1322         .header("Cache-Control", "only-if-cached")
   1323         .build();
   1324 
   1325     executeSynchronously(request)
   1326         .assertCode(504)
   1327         .assertBody("")
   1328         .assertNoNetworkResponse()
   1329         .assertNoCacheResponse();
   1330   }
   1331 
   1332   @Test public void redirect() throws Exception {
   1333     server.enqueue(new MockResponse()
   1334         .setResponseCode(301)
   1335         .addHeader("Location: /b")
   1336         .addHeader("Test", "Redirect from /a to /b")
   1337         .setBody("/a has moved!"));
   1338     server.enqueue(new MockResponse()
   1339         .setResponseCode(302)
   1340         .addHeader("Location: /c")
   1341         .addHeader("Test", "Redirect from /b to /c")
   1342         .setBody("/b has moved!"));
   1343     server.enqueue(new MockResponse().setBody("C"));
   1344 
   1345     executeSynchronously(new Request.Builder().url(server.url("/a")).build())
   1346         .assertCode(200)
   1347         .assertBody("C")
   1348         .priorResponse()
   1349         .assertCode(302)
   1350         .assertHeader("Test", "Redirect from /b to /c")
   1351         .priorResponse()
   1352         .assertCode(301)
   1353         .assertHeader("Test", "Redirect from /a to /b");
   1354 
   1355     assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection.
   1356     assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused.
   1357     assertEquals(2, server.takeRequest().getSequenceNumber()); // Connection reused again!
   1358   }
   1359 
   1360   @Test public void postRedirectsToGet() throws Exception {
   1361     server.enqueue(new MockResponse()
   1362         .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
   1363         .addHeader("Location: /page2")
   1364         .setBody("This page has moved!"));
   1365     server.enqueue(new MockResponse().setBody("Page 2"));
   1366 
   1367     Response response = client.newCall(new Request.Builder()
   1368         .url(server.url("/page1"))
   1369         .post(RequestBody.create(MediaType.parse("text/plain"), "Request Body"))
   1370         .build()).execute();
   1371     assertEquals("Page 2", response.body().string());
   1372 
   1373     RecordedRequest page1 = server.takeRequest();
   1374     assertEquals("POST /page1 HTTP/1.1", page1.getRequestLine());
   1375     assertEquals("Request Body", page1.getBody().readUtf8());
   1376 
   1377     RecordedRequest page2 = server.takeRequest();
   1378     assertEquals("GET /page2 HTTP/1.1", page2.getRequestLine());
   1379   }
   1380 
   1381   @Test public void propfindRedirectsToPropfind() throws Exception {
   1382     server.enqueue(new MockResponse()
   1383         .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
   1384         .addHeader("Location: /page2")
   1385         .setBody("This page has moved!"));
   1386     server.enqueue(new MockResponse().setBody("Page 2"));
   1387 
   1388     Response response = client.newCall(new Request.Builder()
   1389         .url(server.url("/page1"))
   1390         .method("PROPFIND", RequestBody.create(MediaType.parse("text/plain"), "Request Body"))
   1391         .build()).execute();
   1392     assertEquals("Page 2", response.body().string());
   1393 
   1394     RecordedRequest page1 = server.takeRequest();
   1395     assertEquals("PROPFIND /page1 HTTP/1.1", page1.getRequestLine());
   1396     assertEquals("Request Body", page1.getBody().readUtf8());
   1397 
   1398     RecordedRequest page2 = server.takeRequest();
   1399     assertEquals("PROPFIND /page2 HTTP/1.1", page2.getRequestLine());
   1400   }
   1401 
   1402   @Test public void redirectsDoNotIncludeTooManyCookies() throws Exception {
   1403     server2.enqueue(new MockResponse().setBody("Page 2"));
   1404     server.enqueue(new MockResponse()
   1405         .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
   1406         .addHeader("Location: " + server2.url("/")));
   1407 
   1408     CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
   1409     HttpCookie cookie = new HttpCookie("c", "cookie");
   1410     cookie.setDomain(server.getCookieDomain());
   1411     cookie.setPath("/");
   1412     String portList = Integer.toString(server.getPort());
   1413     cookie.setPortlist(portList);
   1414     cookieManager.getCookieStore().add(server.url("/").uri(), cookie);
   1415     client.setCookieHandler(cookieManager);
   1416 
   1417     Response response = client.newCall(new Request.Builder()
   1418         .url(server.url("/page1"))
   1419         .build()).execute();
   1420     assertEquals("Page 2", response.body().string());
   1421 
   1422     RecordedRequest request1 = server.takeRequest();
   1423     assertEquals("$Version=\"1\"; c=\"cookie\";$Path=\"/\";$Domain=\""
   1424         + server.getCookieDomain()
   1425         + "\";$Port=\""
   1426         + portList
   1427         + "\"", request1.getHeader("Cookie"));
   1428 
   1429     RecordedRequest request2 = server2.takeRequest();
   1430     assertNull(request2.getHeader("Cookie"));
   1431   }
   1432 
   1433   @Test public void redirectsDoNotIncludeTooManyAuthHeaders() throws Exception {
   1434     server2.enqueue(new MockResponse().setBody("Page 2"));
   1435     server.enqueue(new MockResponse()
   1436         .setResponseCode(401));
   1437     server.enqueue(new MockResponse()
   1438         .setResponseCode(302)
   1439         .addHeader("Location: " + server2.url("/b")));
   1440 
   1441     client.setAuthenticator(new RecordingOkAuthenticator(Credentials.basic("jesse", "secret")));
   1442 
   1443     Request request = new Request.Builder().url(server.url("/a")).build();
   1444     Response response = client.newCall(request).execute();
   1445     assertEquals("Page 2", response.body().string());
   1446 
   1447     RecordedRequest redirectRequest = server2.takeRequest();
   1448     assertNull(redirectRequest.getHeader("Authorization"));
   1449     assertEquals("/b", redirectRequest.getPath());
   1450   }
   1451 
   1452   @Test public void redirect_Async() throws Exception {
   1453     server.enqueue(new MockResponse()
   1454         .setResponseCode(301)
   1455         .addHeader("Location: /b")
   1456         .addHeader("Test", "Redirect from /a to /b")
   1457         .setBody("/a has moved!"));
   1458     server.enqueue(new MockResponse()
   1459         .setResponseCode(302)
   1460         .addHeader("Location: /c")
   1461         .addHeader("Test", "Redirect from /b to /c")
   1462         .setBody("/b has moved!"));
   1463     server.enqueue(new MockResponse().setBody("C"));
   1464 
   1465     Request request = new Request.Builder().url(server.url("/a")).build();
   1466     client.newCall(request).enqueue(callback);
   1467 
   1468     callback.await(server.url("/c"))
   1469         .assertCode(200)
   1470         .assertBody("C")
   1471         .priorResponse()
   1472         .assertCode(302)
   1473         .assertHeader("Test", "Redirect from /b to /c")
   1474         .priorResponse()
   1475         .assertCode(301)
   1476         .assertHeader("Test", "Redirect from /a to /b");
   1477 
   1478     assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection.
   1479     assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused.
   1480     assertEquals(2, server.takeRequest().getSequenceNumber()); // Connection reused again!
   1481   }
   1482 
   1483   @Test public void follow20Redirects() throws Exception {
   1484     for (int i = 0; i < 20; i++) {
   1485       server.enqueue(new MockResponse()
   1486           .setResponseCode(301)
   1487           .addHeader("Location: /" + (i + 1))
   1488           .setBody("Redirecting to /" + (i + 1)));
   1489     }
   1490     server.enqueue(new MockResponse().setBody("Success!"));
   1491 
   1492     executeSynchronously(new Request.Builder().url(server.url("/0")).build())
   1493         .assertCode(200)
   1494         .assertBody("Success!");
   1495   }
   1496 
   1497   @Test public void follow20Redirects_Async() throws Exception {
   1498     for (int i = 0; i < 20; i++) {
   1499       server.enqueue(new MockResponse()
   1500           .setResponseCode(301)
   1501           .addHeader("Location: /" + (i + 1))
   1502           .setBody("Redirecting to /" + (i + 1)));
   1503     }
   1504     server.enqueue(new MockResponse().setBody("Success!"));
   1505 
   1506     Request request = new Request.Builder().url(server.url("/0")).build();
   1507     client.newCall(request).enqueue(callback);
   1508     callback.await(server.url("/20"))
   1509         .assertCode(200)
   1510         .assertBody("Success!");
   1511   }
   1512 
   1513   @Test public void doesNotFollow21Redirects() throws Exception {
   1514     for (int i = 0; i < 21; i++) {
   1515       server.enqueue(new MockResponse()
   1516           .setResponseCode(301)
   1517           .addHeader("Location: /" + (i + 1))
   1518           .setBody("Redirecting to /" + (i + 1)));
   1519     }
   1520 
   1521     try {
   1522       client.newCall(new Request.Builder().url(server.url("/0")).build()).execute();
   1523       fail();
   1524     } catch (IOException expected) {
   1525       assertEquals("Too many follow-up requests: 21", expected.getMessage());
   1526     }
   1527   }
   1528 
   1529   @Test public void doesNotFollow21Redirects_Async() throws Exception {
   1530     for (int i = 0; i < 21; i++) {
   1531       server.enqueue(new MockResponse()
   1532           .setResponseCode(301)
   1533           .addHeader("Location: /" + (i + 1))
   1534           .setBody("Redirecting to /" + (i + 1)));
   1535     }
   1536 
   1537     Request request = new Request.Builder().url(server.url("/0")).build();
   1538     client.newCall(request).enqueue(callback);
   1539     callback.await(server.url("/20")).assertFailure("Too many follow-up requests: 21");
   1540   }
   1541 
   1542   @Test public void http204WithBodyDisallowed() throws IOException {
   1543     server.enqueue(new MockResponse()
   1544         .setResponseCode(204)
   1545         .setBody("I'm not even supposed to be here today."));
   1546 
   1547     try {
   1548       executeSynchronously(new Request.Builder().url(server.url("/")).build());
   1549       fail();
   1550     } catch (ProtocolException e) {
   1551       assertEquals("HTTP 204 had non-zero Content-Length: 39", e.getMessage());
   1552     }
   1553   }
   1554 
   1555   @Test public void http205WithBodyDisallowed() throws IOException {
   1556     server.enqueue(new MockResponse()
   1557         .setResponseCode(205)
   1558         .setBody("I'm not even supposed to be here today."));
   1559 
   1560     try {
   1561       executeSynchronously(new Request.Builder().url(server.url("/")).build());
   1562       fail();
   1563     } catch (ProtocolException e) {
   1564       assertEquals("HTTP 205 had non-zero Content-Length: 39", e.getMessage());
   1565     }
   1566   }
   1567 
   1568   @Test public void canceledBeforeExecute() throws Exception {
   1569     Call call = client.newCall(new Request.Builder().url(server.url("/a")).build());
   1570     call.cancel();
   1571 
   1572     try {
   1573       call.execute();
   1574       fail();
   1575     } catch (IOException expected) {
   1576     }
   1577     assertEquals(0, server.getRequestCount());
   1578   }
   1579 
   1580   @Test public void cancelDuringHttpConnect() throws Exception {
   1581     cancelDuringConnect("http");
   1582   }
   1583 
   1584   @Test public void cancelDuringHttpsConnect() throws Exception {
   1585     cancelDuringConnect("https");
   1586   }
   1587 
   1588   /** Cancel a call that's waiting for connect to complete. */
   1589   private void cancelDuringConnect(String scheme) throws Exception {
   1590     InetSocketAddress socketAddress = startNullServer();
   1591 
   1592     HttpUrl url = new HttpUrl.Builder()
   1593         .scheme(scheme)
   1594         .host(socketAddress.getHostName())
   1595         .port(socketAddress.getPort())
   1596         .build();
   1597 
   1598     long cancelDelayMillis = 300L;
   1599     Call call = client.newCall(new Request.Builder().url(url).build());
   1600     cancelLater(call, cancelDelayMillis);
   1601 
   1602     long startNanos = System.nanoTime();
   1603     try {
   1604       call.execute();
   1605       fail();
   1606     } catch (IOException expected) {
   1607     }
   1608     long elapsedNanos = System.nanoTime() - startNanos;
   1609     assertEquals(cancelDelayMillis, TimeUnit.NANOSECONDS.toMillis(elapsedNanos), 100f);
   1610   }
   1611 
   1612   private InetSocketAddress startNullServer() throws IOException {
   1613     InetSocketAddress address = new InetSocketAddress(InetAddress.getByName("localhost"), 0);
   1614     nullServer = ServerSocketFactory.getDefault().createServerSocket();
   1615     nullServer.bind(address);
   1616     return new InetSocketAddress(address.getAddress(), nullServer.getLocalPort());
   1617   }
   1618 
   1619   @Test public void cancelTagImmediatelyAfterEnqueue() throws Exception {
   1620     server.enqueue(new MockResponse());
   1621     Call call = client.newCall(new Request.Builder()
   1622         .url(server.url("/a"))
   1623         .tag("request")
   1624         .build());
   1625     call.enqueue(callback);
   1626     client.cancel("request");
   1627     callback.await(server.url("/a")).assertFailure("Canceled");
   1628   }
   1629 
   1630   @Test public void cancelBeforeBodyIsRead() throws Exception {
   1631     server.enqueue(new MockResponse().setBody("def").throttleBody(1, 750, TimeUnit.MILLISECONDS));
   1632 
   1633     final Call call = client.newCall(new Request.Builder().url(server.url("/a")).build());
   1634     ExecutorService executor = Executors.newSingleThreadExecutor();
   1635     Future<Response> result = executor.submit(new Callable<Response>() {
   1636       @Override public Response call() throws Exception {
   1637         return call.execute();
   1638       }
   1639     });
   1640 
   1641     Thread.sleep(100); // wait for it to go in flight.
   1642 
   1643     call.cancel();
   1644     try {
   1645       result.get().body().bytes();
   1646       fail();
   1647     } catch (IOException expected) {
   1648     }
   1649     assertEquals(1, server.getRequestCount());
   1650   }
   1651 
   1652   @Test public void cancelInFlightBeforeResponseReadThrowsIOE() throws Exception {
   1653     server.setDispatcher(new Dispatcher() {
   1654       @Override public MockResponse dispatch(RecordedRequest request) {
   1655         client.cancel("request");
   1656         return new MockResponse().setBody("A");
   1657       }
   1658     });
   1659 
   1660     Request request = new Request.Builder().url(server.url("/a")).tag("request").build();
   1661     try {
   1662       client.newCall(request).execute();
   1663       fail();
   1664     } catch (IOException expected) {
   1665     }
   1666   }
   1667 
   1668   @Test public void cancelInFlightBeforeResponseReadThrowsIOE_HTTPS() throws Exception {
   1669     enableTls();
   1670     cancelInFlightBeforeResponseReadThrowsIOE();
   1671   }
   1672 
   1673   @Test public void cancelInFlightBeforeResponseReadThrowsIOE_HTTP_2() throws Exception {
   1674     enableProtocol(Protocol.HTTP_2);
   1675     cancelInFlightBeforeResponseReadThrowsIOE();
   1676   }
   1677 
   1678   @Test public void cancelInFlightBeforeResponseReadThrowsIOE_SPDY_3() throws Exception {
   1679     enableProtocol(Protocol.SPDY_3);
   1680     cancelInFlightBeforeResponseReadThrowsIOE();
   1681   }
   1682 
   1683   /**
   1684    * This test puts a request in front of one that is to be canceled, so that it is canceled before
   1685    * I/O takes place.
   1686    */
   1687   @Test public void canceledBeforeIOSignalsOnFailure() throws Exception {
   1688     client.getDispatcher().setMaxRequests(1); // Force requests to be executed serially.
   1689     server.setDispatcher(new Dispatcher() {
   1690       char nextResponse = 'A';
   1691 
   1692       @Override public MockResponse dispatch(RecordedRequest request) {
   1693         client.cancel("request B");
   1694         return new MockResponse().setBody(Character.toString(nextResponse++));
   1695       }
   1696     });
   1697 
   1698     Request requestA = new Request.Builder().url(server.url("/a")).tag("request A").build();
   1699     client.newCall(requestA).enqueue(callback);
   1700     assertEquals("/a", server.takeRequest().getPath());
   1701 
   1702     Request requestB = new Request.Builder().url(server.url("/b")).tag("request B").build();
   1703     client.newCall(requestB).enqueue(callback);
   1704 
   1705     callback.await(requestA.httpUrl()).assertBody("A");
   1706     // At this point we know the callback is ready, and that it will receive a cancel failure.
   1707     callback.await(requestB.httpUrl()).assertFailure("Canceled");
   1708   }
   1709 
   1710   @Test public void canceledBeforeIOSignalsOnFailure_HTTPS() throws Exception {
   1711     enableTls();
   1712     canceledBeforeIOSignalsOnFailure();
   1713   }
   1714 
   1715   @Test public void canceledBeforeIOSignalsOnFailure_HTTP_2() throws Exception {
   1716     enableProtocol(Protocol.HTTP_2);
   1717     canceledBeforeIOSignalsOnFailure();
   1718   }
   1719 
   1720   @Test public void canceledBeforeIOSignalsOnFailure_SPDY_3() throws Exception {
   1721     enableProtocol(Protocol.SPDY_3);
   1722     canceledBeforeIOSignalsOnFailure();
   1723   }
   1724 
   1725   @Test public void canceledBeforeResponseReadSignalsOnFailure() throws Exception {
   1726     Request requestA = new Request.Builder().url(server.url("/a")).tag("request A").build();
   1727     final Call call = client.newCall(requestA);
   1728     server.setDispatcher(new Dispatcher() {
   1729       @Override public MockResponse dispatch(RecordedRequest request) {
   1730         call.cancel();
   1731         return new MockResponse().setBody("A");
   1732       }
   1733     });
   1734 
   1735     call.enqueue(callback);
   1736     assertEquals("/a", server.takeRequest().getPath());
   1737 
   1738     callback.await(requestA.httpUrl()).assertFailure("Canceled", "stream was reset: CANCEL",
   1739         "Socket closed");
   1740   }
   1741 
   1742   @Test public void canceledBeforeResponseReadSignalsOnFailure_HTTPS() throws Exception {
   1743     enableTls();
   1744     canceledBeforeResponseReadSignalsOnFailure();
   1745   }
   1746 
   1747   @Test public void canceledBeforeResponseReadSignalsOnFailure_HTTP_2() throws Exception {
   1748     enableProtocol(Protocol.HTTP_2);
   1749     canceledBeforeResponseReadSignalsOnFailure();
   1750   }
   1751 
   1752   @Test public void canceledBeforeResponseReadSignalsOnFailure_SPDY_3() throws Exception {
   1753     enableProtocol(Protocol.SPDY_3);
   1754     canceledBeforeResponseReadSignalsOnFailure();
   1755   }
   1756 
   1757   /**
   1758    * There's a race condition where the cancel may apply after the stream has already been
   1759    * processed.
   1760    */
   1761   @Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce() throws Exception {
   1762     server.enqueue(new MockResponse().setBody("A"));
   1763 
   1764     final CountDownLatch latch = new CountDownLatch(1);
   1765     final AtomicReference<String> bodyRef = new AtomicReference<>();
   1766     final AtomicBoolean failureRef = new AtomicBoolean();
   1767 
   1768     Request request = new Request.Builder().url(server.url("/a")).tag("request A").build();
   1769     final Call call = client.newCall(request);
   1770     call.enqueue(new Callback() {
   1771       @Override public void onFailure(Request request, IOException e) {
   1772         failureRef.set(true);
   1773         latch.countDown();
   1774       }
   1775 
   1776       @Override public void onResponse(Response response) throws IOException {
   1777         call.cancel();
   1778         try {
   1779           bodyRef.set(response.body().string());
   1780         } catch (IOException e) { // It is ok if this broke the stream.
   1781           bodyRef.set("A");
   1782           throw e; // We expect to not loop into onFailure in this case.
   1783         } finally {
   1784           latch.countDown();
   1785         }
   1786       }
   1787     });
   1788 
   1789     latch.await();
   1790     assertEquals("A", bodyRef.get());
   1791     assertFalse(failureRef.get());
   1792   }
   1793 
   1794   @Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_HTTPS()
   1795       throws Exception {
   1796     enableTls();
   1797     canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce();
   1798   }
   1799 
   1800   @Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_HTTP_2()
   1801       throws Exception {
   1802     enableProtocol(Protocol.HTTP_2);
   1803     canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce();
   1804   }
   1805 
   1806   @Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_SPDY_3()
   1807       throws Exception {
   1808     enableProtocol(Protocol.SPDY_3);
   1809     canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce();
   1810   }
   1811 
   1812   @Test public void cancelWithInterceptor() throws Exception {
   1813     client.interceptors().add(new Interceptor() {
   1814       @Override public Response intercept(Chain chain) throws IOException {
   1815         chain.proceed(chain.request());
   1816         throw new AssertionError(); // We expect an exception.
   1817       }
   1818     });
   1819 
   1820     Call call = client.newCall(new Request.Builder().url(server.url("/a")).build());
   1821     call.cancel();
   1822 
   1823     try {
   1824       call.execute();
   1825       fail();
   1826     } catch (IOException expected) {
   1827     }
   1828     assertEquals(0, server.getRequestCount());
   1829   }
   1830 
   1831   @Test public void gzip() throws Exception {
   1832     Buffer gzippedBody = gzip("abcabcabc");
   1833     String bodySize = Long.toString(gzippedBody.size());
   1834 
   1835     server.enqueue(new MockResponse()
   1836         .setBody(gzippedBody)
   1837         .addHeader("Content-Encoding: gzip"));
   1838 
   1839     Request request = new Request.Builder()
   1840         .url(server.url("/"))
   1841         .build();
   1842 
   1843     // Confirm that the user request doesn't have Accept-Encoding, and the user
   1844     // response doesn't have a Content-Encoding or Content-Length.
   1845     RecordedResponse userResponse = executeSynchronously(request);
   1846     userResponse.assertCode(200)
   1847         .assertRequestHeader("Accept-Encoding")
   1848         .assertHeader("Content-Encoding")
   1849         .assertHeader("Content-Length")
   1850         .assertBody("abcabcabc");
   1851 
   1852     // But the network request doesn't lie. OkHttp used gzip for this call.
   1853     userResponse.networkResponse()
   1854         .assertHeader("Content-Encoding", "gzip")
   1855         .assertHeader("Content-Length", bodySize)
   1856         .assertRequestHeader("Accept-Encoding", "gzip");
   1857   }
   1858 
   1859   /** https://github.com/square/okhttp/issues/1927 */
   1860   @Test public void gzipResponseAfterAuthenticationChallenge() throws Exception {
   1861     server.enqueue(new MockResponse()
   1862         .setResponseCode(401));
   1863     server.enqueue(new MockResponse()
   1864         .setBody(gzip("abcabcabc"))
   1865         .addHeader("Content-Encoding: gzip"));
   1866     client.setAuthenticator(new RecordingOkAuthenticator("password"));
   1867 
   1868     Request request = new Request.Builder()
   1869         .url(server.url("/"))
   1870         .build();
   1871     executeSynchronously(request)
   1872         .assertBody("abcabcabc");
   1873   }
   1874 
   1875   @Test public void asyncResponseCanBeConsumedLater() throws Exception {
   1876     server.enqueue(new MockResponse().setBody("abc"));
   1877     server.enqueue(new MockResponse().setBody("def"));
   1878 
   1879     Request request = new Request.Builder()
   1880         .url(server.url("/"))
   1881         .header("User-Agent", "SyncApiTest")
   1882         .build();
   1883 
   1884     final BlockingQueue<Response> responseRef = new SynchronousQueue<>();
   1885     client.newCall(request).enqueue(new Callback() {
   1886       @Override public void onFailure(Request request, IOException e) {
   1887         throw new AssertionError();
   1888       }
   1889 
   1890       @Override public void onResponse(Response response) throws IOException {
   1891         try {
   1892           responseRef.put(response);
   1893         } catch (InterruptedException e) {
   1894           throw new AssertionError();
   1895         }
   1896       }
   1897     });
   1898 
   1899     Response response = responseRef.take();
   1900     assertEquals(200, response.code());
   1901     assertEquals("abc", response.body().string());
   1902 
   1903     // Make another request just to confirm that that connection can be reused...
   1904     executeSynchronously(new Request.Builder().url(server.url("/")).build()).assertBody("def");
   1905     assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection.
   1906     assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused.
   1907 
   1908     // ... even before we close the response body!
   1909     response.body().close();
   1910   }
   1911 
   1912   @Test public void userAgentIsIncludedByDefault() throws Exception {
   1913     server.enqueue(new MockResponse());
   1914 
   1915     executeSynchronously(new Request.Builder().url(server.url("/")).build());
   1916 
   1917     RecordedRequest recordedRequest = server.takeRequest();
   1918     assertTrue(recordedRequest.getHeader("User-Agent")
   1919         .matches(Version.userAgent()));
   1920   }
   1921 
   1922   @Test public void setFollowRedirectsFalse() throws Exception {
   1923     server.enqueue(new MockResponse()
   1924         .setResponseCode(302)
   1925         .addHeader("Location: /b")
   1926         .setBody("A"));
   1927     server.enqueue(new MockResponse().setBody("B"));
   1928 
   1929     client.setFollowRedirects(false);
   1930     RecordedResponse recordedResponse = executeSynchronously(
   1931         new Request.Builder().url(server.url("/a")).build());
   1932 
   1933     recordedResponse
   1934         .assertBody("A")
   1935         .assertCode(302);
   1936   }
   1937 
   1938   @Test public void expect100ContinueNonEmptyRequestBody() throws Exception {
   1939     server.enqueue(new MockResponse());
   1940 
   1941     Request request = new Request.Builder()
   1942         .url(server.url("/"))
   1943         .header("Expect", "100-continue")
   1944         .post(RequestBody.create(MediaType.parse("text/plain"), "abc"))
   1945         .build();
   1946 
   1947     executeSynchronously(request)
   1948         .assertCode(200)
   1949         .assertSuccessful();
   1950 
   1951     assertEquals("abc", server.takeRequest().getBody().readUtf8());
   1952   }
   1953 
   1954   @Test public void expect100ContinueEmptyRequestBody() throws Exception {
   1955     server.enqueue(new MockResponse());
   1956 
   1957     Request request = new Request.Builder()
   1958         .url(server.url("/"))
   1959         .header("Expect", "100-continue")
   1960         .post(RequestBody.create(MediaType.parse("text/plain"), ""))
   1961         .build();
   1962 
   1963     executeSynchronously(request)
   1964         .assertCode(200)
   1965         .assertSuccessful();
   1966   }
   1967 
   1968   /** We forbid non-ASCII characters in outgoing request headers, but accept UTF-8. */
   1969   @Test public void responseHeaderParsingIsLenient() throws Exception {
   1970     Headers headers = new Headers.Builder()
   1971         .add("Content-Length", "0")
   1972         .addLenient("a\tb: c\u007fd")
   1973         .addLenient(": ef")
   1974         .addLenient("\ud83c\udf69: \u2615\ufe0f")
   1975         .build();
   1976     server.enqueue(new MockResponse().setHeaders(headers));
   1977 
   1978     Request request = new Request.Builder()
   1979         .url(server.url("/"))
   1980         .build();
   1981 
   1982     executeSynchronously(request)
   1983         .assertHeader("a\tb", "c\u007fd")
   1984         .assertHeader("\ud83c\udf69", "\u2615\ufe0f")
   1985         .assertHeader("", "ef");
   1986   }
   1987 
   1988   @Test public void customDns() throws Exception {
   1989     // Configure a DNS that returns our MockWebServer for every hostname.
   1990     FakeDns dns = new FakeDns();
   1991     dns.addresses(Dns.SYSTEM.lookup(server.url("/").host()));
   1992     client.setDns(dns);
   1993 
   1994     server.enqueue(new MockResponse());
   1995     Request request = new Request.Builder()
   1996         .url(server.url("/").newBuilder().host("android.com").build())
   1997         .build();
   1998     executeSynchronously(request).assertCode(200);
   1999 
   2000     dns.assertRequests("android.com");
   2001   }
   2002 
   2003   /** We had a bug where failed HTTP/2 calls could break the entire connection. */
   2004   @Test public void failingCallsDoNotInterfereWithConnection() throws Exception {
   2005     enableProtocol(Protocol.HTTP_2);
   2006 
   2007     server.enqueue(new MockResponse().setBody("Response 1"));
   2008     server.enqueue(new MockResponse().setBody("Response 2"));
   2009 
   2010     RequestBody requestBody = new RequestBody() {
   2011       @Override public MediaType contentType() {
   2012         return null;
   2013       }
   2014 
   2015       @Override public void writeTo(BufferedSink sink) throws IOException {
   2016         sink.writeUtf8("abc");
   2017         sink.flush();
   2018 
   2019         makeFailingCall();
   2020 
   2021         sink.writeUtf8("def");
   2022         sink.flush();
   2023       }
   2024     };
   2025     Call call = client.newCall(new Request.Builder()
   2026         .url(server.url("/"))
   2027         .post(requestBody)
   2028         .build());
   2029     assertEquals("Response 1", call.execute().body().string());
   2030   }
   2031 
   2032   /** Test which headers are sent unencrypted to the HTTP proxy. */
   2033   @Test public void proxyConnectOmitsApplicationHeaders() throws Exception {
   2034     server.useHttps(sslContext.getSocketFactory(), true);
   2035     server.enqueue(new MockResponse()
   2036         .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
   2037         .clearHeaders());
   2038     server.enqueue(new MockResponse()
   2039         .setBody("encrypted response from the origin server"));
   2040 
   2041     client.setSslSocketFactory(sslContext.getSocketFactory());
   2042     client.setProxy(server.toProxyAddress());
   2043     RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
   2044     client.setHostnameVerifier(hostnameVerifier);
   2045 
   2046     Request request = new Request.Builder()
   2047         .url("https://android.com/foo")
   2048         .header("Private", "Secret")
   2049         .header("User-Agent", "App 1.0")
   2050         .build();
   2051     Response response = client.newCall(request).execute();
   2052     assertEquals("encrypted response from the origin server", response.body().string());
   2053 
   2054     RecordedRequest connect = server.takeRequest();
   2055     assertNull(connect.getHeader("Private"));
   2056     assertEquals(Version.userAgent(), connect.getHeader("User-Agent"));
   2057     assertEquals("Keep-Alive", connect.getHeader("Proxy-Connection"));
   2058     assertEquals("android.com:443", connect.getHeader("Host"));
   2059 
   2060     RecordedRequest get = server.takeRequest();
   2061     assertEquals("Secret", get.getHeader("Private"));
   2062     assertEquals("App 1.0", get.getHeader("User-Agent"));
   2063 
   2064     assertEquals(Arrays.asList("verify android.com"), hostnameVerifier.calls);
   2065   }
   2066 
   2067   /** Respond to a proxy authorization challenge. */
   2068   @Test public void proxyAuthenticateOnConnect() throws Exception {
   2069     server.useHttps(sslContext.getSocketFactory(), true);
   2070     server.enqueue(new MockResponse()
   2071         .setResponseCode(407)
   2072         .addHeader("Proxy-Authenticate: Basic realm=\"localhost\""));
   2073     server.enqueue(new MockResponse()
   2074         .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
   2075         .clearHeaders());
   2076     server.enqueue(new MockResponse()
   2077         .setBody("response body"));
   2078 
   2079     client.setSslSocketFactory(sslContext.getSocketFactory());
   2080     client.setProxy(server.toProxyAddress());
   2081     client.setAuthenticator(new RecordingOkAuthenticator("password"));
   2082     client.setHostnameVerifier(new RecordingHostnameVerifier());
   2083 
   2084     Request request = new Request.Builder()
   2085         .url("https://android.com/foo")
   2086         .build();
   2087     Response response = client.newCall(request).execute();
   2088     assertEquals("response body", response.body().string());
   2089 
   2090     RecordedRequest connect1 = server.takeRequest();
   2091     assertEquals("CONNECT android.com:443 HTTP/1.1", connect1.getRequestLine());
   2092     assertNull(connect1.getHeader("Proxy-Authorization"));
   2093 
   2094     RecordedRequest connect2 = server.takeRequest();
   2095     assertEquals("CONNECT android.com:443 HTTP/1.1", connect2.getRequestLine());
   2096     assertEquals("password", connect2.getHeader("Proxy-Authorization"));
   2097 
   2098     RecordedRequest get = server.takeRequest();
   2099     assertEquals("GET /foo HTTP/1.1", get.getRequestLine());
   2100     assertNull(get.getHeader("Proxy-Authorization"));
   2101   }
   2102 
   2103   /**
   2104    * Confirm that we don't send the Proxy-Authorization header from the request to the proxy server.
   2105    * We used to have that behavior but it is problematic because unrelated requests end up sharing
   2106    * credentials. Worse, that approach leaks proxy credentials to the origin server.
   2107    */
   2108   @Test public void noProactiveProxyAuthorization() throws Exception {
   2109     server.useHttps(sslContext.getSocketFactory(), true);
   2110     server.enqueue(new MockResponse()
   2111         .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
   2112         .clearHeaders());
   2113     server.enqueue(new MockResponse()
   2114         .setBody("response body"));
   2115 
   2116     client.setSslSocketFactory(sslContext.getSocketFactory());
   2117     client.setProxy(server.toProxyAddress());
   2118     client.setHostnameVerifier(new RecordingHostnameVerifier());
   2119 
   2120     Request request = new Request.Builder()
   2121         .url("https://android.com/foo")
   2122         .header("Proxy-Authorization", "password")
   2123         .build();
   2124     Response response = client.newCall(request).execute();
   2125     assertEquals("response body", response.body().string());
   2126 
   2127     RecordedRequest connect = server.takeRequest();
   2128     assertNull(connect.getHeader("Proxy-Authorization"));
   2129 
   2130     RecordedRequest get = server.takeRequest();
   2131     assertEquals("password", get.getHeader("Proxy-Authorization"));
   2132   }
   2133 
   2134   /** https://github.com/square/okhttp/issues/2344 */
   2135   @Test public void ipv6HostHasSquareBraces() throws Exception {
   2136     // Use a proxy to fake IPv6 connectivity, even if localhost doesn't have IPv6.
   2137     server.useHttps(sslContext.getSocketFactory(), true);
   2138     server.setProtocols(Collections.singletonList(Protocol.HTTP_1_1));
   2139     server.enqueue(new MockResponse()
   2140         .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
   2141         .clearHeaders());
   2142     server.enqueue(new MockResponse()
   2143         .setBody("response body"));
   2144 
   2145     client
   2146         .setSslSocketFactory(sslContext.getSocketFactory())
   2147         .setHostnameVerifier(new RecordingHostnameVerifier())
   2148         .setProxy(server.toProxyAddress());
   2149 
   2150     Request request = new Request.Builder()
   2151         .url("https://[::1]/")
   2152         .build();
   2153     Response response = client.newCall(request).execute();
   2154     assertEquals("response body", response.body().string());
   2155 
   2156     RecordedRequest connect = server.takeRequest();
   2157     assertEquals("CONNECT [::1]:443 HTTP/1.1", connect.getRequestLine());
   2158     assertEquals("[::1]:443", connect.getHeader("Host"));
   2159 
   2160     RecordedRequest get = server.takeRequest();
   2161     assertEquals("GET / HTTP/1.1", get.getRequestLine());
   2162     assertEquals("[::1]", get.getHeader("Host"));
   2163   }
   2164 
   2165   private void makeFailingCall() {
   2166     RequestBody requestBody = new RequestBody() {
   2167       @Override public MediaType contentType() {
   2168         return null;
   2169       }
   2170 
   2171       @Override public long contentLength() throws IOException {
   2172         return 1;
   2173       }
   2174 
   2175       @Override public void writeTo(BufferedSink sink) throws IOException {
   2176         throw new IOException("write body fail!");
   2177       }
   2178     };
   2179     Call call = client.newCall(new Request.Builder()
   2180         .url(server.url("/"))
   2181         .post(requestBody)
   2182         .build());
   2183     try {
   2184       call.execute();
   2185       fail();
   2186     } catch (IOException expected) {
   2187       assertEquals("write body fail!", expected.getMessage());
   2188     }
   2189   }
   2190 
   2191   private RecordedResponse executeSynchronously(Request request) throws IOException {
   2192     Response response = client.newCall(request).execute();
   2193     return new RecordedResponse(request, response, null, response.body().string(), null);
   2194   }
   2195 
   2196   /**
   2197    * Tests that use this will fail unless boot classpath is set. Ex. {@code
   2198    * -Xbootclasspath/p:/tmp/alpn-boot-8.0.0.v20140317}
   2199    */
   2200   private void enableProtocol(Protocol protocol) {
   2201     enableTls();
   2202     client.setProtocols(Arrays.asList(protocol, Protocol.HTTP_1_1));
   2203     server.setProtocols(client.getProtocols());
   2204   }
   2205 
   2206   private void enableTls() {
   2207     client.setSslSocketFactory(sslContext.getSocketFactory());
   2208     client.setHostnameVerifier(new RecordingHostnameVerifier());
   2209     server.useHttps(sslContext.getSocketFactory(), false);
   2210   }
   2211 
   2212   private Buffer gzip(String data) throws IOException {
   2213     Buffer result = new Buffer();
   2214     BufferedSink sink = Okio.buffer(new GzipSink(result));
   2215     sink.writeUtf8(data);
   2216     sink.close();
   2217     return result;
   2218   }
   2219 
   2220   private void cancelLater(final Call call, final long delay) {
   2221     new Thread("canceler") {
   2222       @Override public void run() {
   2223         try {
   2224           Thread.sleep(delay);
   2225         } catch (InterruptedException e) {
   2226           throw new AssertionError();
   2227         }
   2228         call.cancel();
   2229       }
   2230     }.start();
   2231   }
   2232 
   2233   private static class RecordingSSLSocketFactory extends DelegatingSSLSocketFactory {
   2234 
   2235     private List<SSLSocket> socketsCreated = new ArrayList<>();
   2236 
   2237     public RecordingSSLSocketFactory(SSLSocketFactory delegate) {
   2238       super(delegate);
   2239     }
   2240 
   2241     @Override
   2242     protected SSLSocket configureSocket(SSLSocket sslSocket) throws IOException {
   2243       socketsCreated.add(sslSocket);
   2244       return sslSocket;
   2245     }
   2246 
   2247     public List<SSLSocket> getSocketsCreated() {
   2248       return socketsCreated;
   2249     }
   2250   }
   2251 
   2252   /**
   2253    * Used during tests that involve TLS connection fallback attempts. OkHttp includes the
   2254    * TLS_FALLBACK_SCSV cipher on fallback connections. See
   2255    * {@link com.squareup.okhttp.FallbackTestClientSocketFactory} for details.
   2256    */
   2257   private void suppressTlsFallbackScsv(OkHttpClient client) {
   2258     FallbackTestClientSocketFactory clientSocketFactory =
   2259         new FallbackTestClientSocketFactory(sslContext.getSocketFactory());
   2260     client.setSslSocketFactory(clientSocketFactory);
   2261   }
   2262 }
   2263