1c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath/*
2c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Copyright (C) 2009 The Android Open Source Project
3c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
4c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Licensed under the Apache License, Version 2.0 (the "License");
5c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * you may not use this file except in compliance with the License.
6c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * You may obtain a copy of the License at
7c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
8c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *      http://www.apache.org/licenses/LICENSE-2.0
9c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath *
10c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * Unless required by applicable law or agreed to in writing, software
11c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * distributed under the License is distributed on an "AS IS" BASIS,
12c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * See the License for the specific language governing permissions and
14c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath * limitations under the License.
15c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath */
16c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
1771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerpackage com.squareup.okhttp;
1871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
19e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.internal.Internal;
2054cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport com.squareup.okhttp.internal.RecordingAuthenticator;
21faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport com.squareup.okhttp.internal.RecordingOkAuthenticator;
22e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.internal.SingleInetAddressNetwork;
232231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport com.squareup.okhttp.internal.SslContextBuilder;
24e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.internal.Util;
2571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport com.squareup.okhttp.internal.Version;
26166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.MockResponse;
27166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.MockWebServer;
28166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.RecordedRequest;
29166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport com.squareup.okhttp.mockwebserver.SocketPolicy;
3071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport com.squareup.okhttp.testing.RecordingHostnameVerifier;
31c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.IOException;
32c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.InputStream;
33c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.io.OutputStream;
34c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.Authenticator;
35c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.ConnectException;
36c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.HttpRetryException;
37c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.HttpURLConnection;
38c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.InetAddress;
39c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.ProtocolException;
40c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.Proxy;
412231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.ProxySelector;
42e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.net.ServerSocket;
43a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colittiimport java.net.Socket;
442231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport java.net.SocketAddress;
45b5f9076b16fcc41c3dad31aecfdcfd962a7a1f75Neil Fullerimport java.net.SocketTimeoutException;
46c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URI;
47c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URL;
48c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.URLConnection;
49c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.net.UnknownHostException;
50c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.security.cert.CertificateException;
51c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.security.cert.X509Certificate;
52c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.ArrayList;
53c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Arrays;
54c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Collections;
55e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.EnumSet;
5671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport java.util.LinkedHashSet;
57c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.List;
58c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Map;
59faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamathimport java.util.Random;
60c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.Set;
6187ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilsonimport java.util.concurrent.TimeUnit;
62c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport java.util.zip.GZIPInputStream;
63e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport javax.net.ServerSocketFactory;
64a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colittiimport javax.net.SocketFactory;
657407d6984ce69693097befc9b72609a8156463bbNarayan Kamathimport javax.net.ssl.HttpsURLConnection;
66c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport javax.net.ssl.SSLContext;
67c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport javax.net.ssl.SSLException;
682231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.SSLHandshakeException;
69c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport javax.net.ssl.SSLSocketFactory;
702231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport javax.net.ssl.TrustManager;
71c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamathimport javax.net.ssl.X509TrustManager;
72e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.Buffer;
73e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.BufferedSink;
74e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.GzipSink;
75e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.Okio;
762231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport org.junit.After;
7754cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport org.junit.Before;
7854cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport org.junit.Ignore;
79e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.Rule;
8054cf3446000fdcf88a9e62724f7deb0282e98da1jwilsonimport org.junit.Test;
81e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.rules.TemporaryFolder;
8254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.Util.UTF_8;
843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.OkHeaders.SELECTED_PROTOCOL;
85e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static com.squareup.okhttp.internal.http.StatusLine.HTTP_PERM_REDIRECT;
863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static com.squareup.okhttp.internal.http.StatusLine.HTTP_TEMP_REDIRECT;
87166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport static com.squareup.okhttp.mockwebserver.SocketPolicy.DISCONNECT_AT_END;
88166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport static com.squareup.okhttp.mockwebserver.SocketPolicy.DISCONNECT_AT_START;
89166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport static com.squareup.okhttp.mockwebserver.SocketPolicy.SHUTDOWN_INPUT_AT_END;
90166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamathimport static com.squareup.okhttp.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END;
913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static java.util.concurrent.TimeUnit.MILLISECONDS;
923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static java.util.concurrent.TimeUnit.NANOSECONDS;
932231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertEquals;
942231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertFalse;
953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertNotNull;
962231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertNull;
972231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.assertTrue;
982231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonimport static org.junit.Assert.fail;
99c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
10054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson/** Android's URLConnectionTest. */
1012231db3e6bb54447a9b14cf004a6cb03c373651cjwilsonpublic final class URLConnectionTest {
10271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Rule public final MockWebServer server = new MockWebServer();
10371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Rule public final MockWebServer server2 = new MockWebServer();
104e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Rule public final TemporaryFolder tempDir = new TemporaryFolder();
10554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
10671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  private SSLContext sslContext = SslContextBuilder.localhost();
107e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private OkUrlFactory client;
1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private HttpURLConnection connection;
109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private Cache cache;
11054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
11154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Before public void setUp() throws Exception {
11271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.setProtocolNegotiationEnabled(false);
113e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client = new OkUrlFactory(new OkHttpClient());
11454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
11554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
11654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @After public void tearDown() throws Exception {
117166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    Authenticator.setDefault(null);
11854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    System.clearProperty("proxyHost");
11954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    System.clearProperty("proxyPort");
120e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    System.clearProperty("http.agent");
12154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    System.clearProperty("http.proxyHost");
12254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    System.clearProperty("http.proxyPort");
12354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    System.clearProperty("https.proxyHost");
12454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    System.clearProperty("https.proxyPort");
12554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (cache != null) {
126faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      cache.delete();
12754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
12854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
12954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
13054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void requestHeaders() throws IOException, InterruptedException {
13154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
13254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.addRequestProperty("D", "e");
1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.addRequestProperty("D", "f");
1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("f", connection.getRequestProperty("D"));
1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("f", connection.getRequestProperty("d"));
1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Map<String, List<String>> requestHeaders = connection.getRequestProperties();
13971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(newSet("e", "f"), new LinkedHashSet<>(requestHeaders.get("D")));
14071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(newSet("e", "f"), new LinkedHashSet<>(requestHeaders.get("d")));
14154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
14254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.put("G", Arrays.asList("h"));
14354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("Modified an unmodifiable view.");
14454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (UnsupportedOperationException expected) {
14554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
14654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
14754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestHeaders.get("D").add("i");
14854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("Modified an unmodifiable view.");
14954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (UnsupportedOperationException expected) {
15054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
15154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
1523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.setRequestProperty(null, "j");
15354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
15454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (NullPointerException expected) {
15554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
15654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
1573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.addRequestProperty(null, "k");
15854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
15954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (NullPointerException expected) {
16054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
1613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setRequestProperty("NullValue", null);
1623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertNull(connection.getRequestProperty("NullValue"));
1633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.addRequestProperty("AnotherNullValue", null);
1643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertNull(connection.getRequestProperty("AnotherNullValue"));
16554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getResponseCode();
16754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(Arrays.asList("e", "f"), request.getHeaders().values("D"));
169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("NullValue"));
170e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("AnotherNullValue"));
171e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("G"));
172e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("null"));
17354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
17454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
1753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.addRequestProperty("N", "o");
17654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("Set header after connect");
17754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
17854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
17954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
1803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.setRequestProperty("P", "q");
18154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("Set header after connect");
18254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
18354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
18454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
1853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.getRequestProperties();
18654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
18754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
18854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
18954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
19054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
19154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getRequestPropertyReturnsLastValue() throws Exception {
1923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
1933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.addRequestProperty("A", "value1");
1943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.addRequestProperty("A", "value2");
1953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("value2", connection.getRequestProperty("A"));
19654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
19754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
19854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void responseHeaders() throws IOException, InterruptedException {
19954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setStatus("HTTP/1.0 200 Fantastic")
20054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("A: c")
20154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("B: d")
20254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("A: e")
20354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setChunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8));
20454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
2063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(200, connection.getResponseCode());
2073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("Fantastic", connection.getResponseMessage());
2083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("HTTP/1.0 200 Fantastic", connection.getHeaderField(null));
2093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Map<String, List<String>> responseHeaders = connection.getHeaderFields();
21054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(Arrays.asList("HTTP/1.0 200 Fantastic"), responseHeaders.get(null));
21171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(newSet("c", "e"), new LinkedHashSet<>(responseHeaders.get("A")));
21271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(newSet("c", "e"), new LinkedHashSet<>(responseHeaders.get("a")));
21354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
21454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      responseHeaders.put("N", Arrays.asList("o"));
21554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("Modified an unmodifiable view.");
21654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (UnsupportedOperationException expected) {
21754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
21854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
21954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      responseHeaders.get("A").add("f");
22054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("Modified an unmodifiable view.");
22154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (UnsupportedOperationException expected) {
22254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
2233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("A", connection.getHeaderFieldKey(0));
2243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("c", connection.getHeaderField(0));
2253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("B", connection.getHeaderFieldKey(1));
2263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("d", connection.getHeaderField(1));
2273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("A", connection.getHeaderFieldKey(2));
2283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("e", connection.getHeaderField(2));
22954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
23054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
23154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void serverSendsInvalidResponseHeaders() throws Exception {
23254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setStatus("HTP/1.1 200 OK"));
23354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
23554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
2363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.getResponseCode();
23754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
23854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
23954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
24054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
24154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
24254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void serverSendsInvalidCodeTooLarge() throws Exception {
24354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setStatus("HTTP/1.1 2147483648 OK"));
24454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
24654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
2473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.getResponseCode();
24854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
24954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
25054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
25154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
25254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
25354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void serverSendsInvalidCodeNotANumber() throws Exception {
25454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setStatus("HTTP/1.1 00a OK"));
25554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
25754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
2583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.getResponseCode();
25954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
26054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
26154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
26254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
26354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
26454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void serverSendsUnnecessaryWhitespace() throws Exception {
26554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setStatus(" HTTP/1.1 2147483648 OK"));
26654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
26854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
2693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.getResponseCode();
27054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
27154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
27254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
27354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
27454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
27554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectRetriesUntilConnectedOrFailed() throws Exception {
27654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = server.getUrl("/foo");
27771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.shutdown();
27854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(url);
28054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
28154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.connect();
28254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
28354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
28454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
28554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
28654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
28754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void requestBodySurvivesRetriesWithFixedLength() throws Exception {
28854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testRequestBodySurvivesRetries(TransferKind.FIXED_LENGTH);
28954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
29054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
29154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void requestBodySurvivesRetriesWithChunkedStreaming() throws Exception {
29254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testRequestBodySurvivesRetries(TransferKind.CHUNKED);
29354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
29454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
29554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void requestBodySurvivesRetriesWithBufferedBody() throws Exception {
29654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testRequestBodySurvivesRetries(TransferKind.END_OF_STREAM);
29754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
29854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
29954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testRequestBodySurvivesRetries(TransferKind transferKind) throws Exception {
30054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("abc"));
30154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
30254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Use a misconfigured proxy to guarantee that the request is retried.
30354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    FakeProxySelector proxySelector = new FakeProxySelector();
30471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    proxySelector.proxies.add(server2.toProxyAddress());
305e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setProxySelector(proxySelector);
30671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server2.shutdown();
30754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
3083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/def"));
30954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
31054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transferKind.setForRequest(connection, 4);
31154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.getOutputStream().write("body".getBytes("UTF-8"));
31254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("abc", connection);
31354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
314e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("body", server.takeRequest().getBody().readUtf8());
31554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
31654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
31754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getErrorStreamOnSuccessfulRequest() throws Exception {
31854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("A"));
3193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
32054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertNull(connection.getErrorStream());
32154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
32254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
32354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getErrorStreamOnUnsuccessfulRequest() throws Exception {
32454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(404).setBody("A"));
3253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
32654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("A", readAscii(connection.getErrorStream(), Integer.MAX_VALUE));
32754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
32854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
32954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // Check that if we don't read to the end of a response, the next request on the
33054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // recycled connection doesn't get the unread tail of the first request's response.
33154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // http://code.google.com/p/android/issues/detail?id=2939
33254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void bug2939() throws Exception {
33354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse().setChunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8);
33454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
33554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
33654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
33754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
33854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDE", client.open(server.getUrl("/")), 5);
33954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDE", client.open(server.getUrl("/")), 5);
34054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
34154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
34254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // Check that we recognize a few basic mime types by extension.
34354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // http://code.google.com/p/android/issues/detail?id=10100
34454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void bug10100() throws Exception {
34554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("image/jpeg", URLConnection.guessContentTypeFromName("someFile.jpg"));
34654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("application/pdf", URLConnection.guessContentTypeFromName("stuff.pdf"));
34754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
34854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
34954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectionsArePooled() throws Exception {
35054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse().setBody("ABCDEFGHIJKLMNOPQR");
35154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
35254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
35354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
35454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
35554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
35654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDEFGHIJKLMNOPQR", client.open(server.getUrl("/foo")));
35754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
35854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDEFGHIJKLMNOPQR", client.open(server.getUrl("/bar?baz=quux")));
35954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, server.takeRequest().getSequenceNumber());
36054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDEFGHIJKLMNOPQR", client.open(server.getUrl("/z")));
36154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(2, server.takeRequest().getSequenceNumber());
36254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
36354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
36454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void chunkedConnectionsArePooled() throws Exception {
36554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse().setChunkedBody("ABCDEFGHIJKLMNOPQR", 5);
36654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
36754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
36854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
36954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
37054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
37154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDEFGHIJKLMNOPQR", client.open(server.getUrl("/foo")));
37254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
37354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDEFGHIJKLMNOPQR", client.open(server.getUrl("/bar?baz=quux")));
37454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, server.takeRequest().getSequenceNumber());
37554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDEFGHIJKLMNOPQR", client.open(server.getUrl("/z")));
37654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(2, server.takeRequest().getSequenceNumber());
37754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
37854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
37954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void serverClosesSocket() throws Exception {
38054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testServerClosesOutput(DISCONNECT_AT_END);
38154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
38254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
38354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void serverShutdownInput() throws Exception {
38454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testServerClosesOutput(SHUTDOWN_INPUT_AT_END);
38554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
38654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
38754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void serverShutdownOutput() throws Exception {
38854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testServerClosesOutput(SHUTDOWN_OUTPUT_AT_END);
38954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
39054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
3913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void invalidHost() throws Exception {
3923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // Note that 1234.1.1.1 is an invalid host in a URI, but URL isn't as strict.
3933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    URL url = new URL("http://1234.1.1.1/index.html");
3943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection = client.open(url);
3953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    try {
3963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.connect();
3973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      fail();
3986dde4fd274c15786415a313faf5b4506e3d712e4jwilson    } catch (UnknownHostException expected) {
3993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
4003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
40254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testServerClosesOutput(SocketPolicy socketPolicy) throws Exception {
40354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("This connection won't pool properly")
40454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setSocketPolicy(socketPolicy));
40554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse responseAfter = new MockResponse().setBody("This comes after a busted connection");
40654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(responseAfter);
40754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(responseAfter); // Enqueue 2x because the broken connection may be reused.
40854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
40954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection connection1 = client.open(server.getUrl("/a"));
41054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection1.setReadTimeout(100);
41154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("This connection won't pool properly", connection1);
41254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
41354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection connection2 = client.open(server.getUrl("/b"));
41454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection2.setReadTimeout(100);
41554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("This comes after a busted connection", connection2);
41654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
41754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Check that a fresh connection was created, either immediately or after attempting reuse.
41854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest requestAfter = server.takeRequest();
41954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (server.getRequestCount() == 3) {
42054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      requestAfter = server.takeRequest(); // The failure consumed a response.
42154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
42254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // sequence number 0 means the HTTP socket connection was not reused
42354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, requestAfter.getSequenceNumber());
42454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
42554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
42654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  enum WriteKind {BYTE_BY_BYTE, SMALL_BUFFERS, LARGE_BUFFERS}
42754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
42854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void chunkedUpload_byteByByte() throws Exception {
42954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    doUpload(TransferKind.CHUNKED, WriteKind.BYTE_BY_BYTE);
43054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
43154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
43254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void chunkedUpload_smallBuffers() throws Exception {
43354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    doUpload(TransferKind.CHUNKED, WriteKind.SMALL_BUFFERS);
43454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
43554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
43654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void chunkedUpload_largeBuffers() throws Exception {
43754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    doUpload(TransferKind.CHUNKED, WriteKind.LARGE_BUFFERS);
43854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
43954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
44054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void fixedLengthUpload_byteByByte() throws Exception {
44154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    doUpload(TransferKind.FIXED_LENGTH, WriteKind.BYTE_BY_BYTE);
44254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
44354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
44454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void fixedLengthUpload_smallBuffers() throws Exception {
44554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    doUpload(TransferKind.FIXED_LENGTH, WriteKind.SMALL_BUFFERS);
44654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
44754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
44854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void fixedLengthUpload_largeBuffers() throws Exception {
44954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    doUpload(TransferKind.FIXED_LENGTH, WriteKind.LARGE_BUFFERS);
45054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
45154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
45254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Exception {
45354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    int n = 512 * 1024;
45471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.setBodyLimit(0);
45554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
45654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
45754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection conn = client.open(server.getUrl("/"));
45854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    conn.setDoOutput(true);
45954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    conn.setRequestMethod("POST");
46054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (uploadKind == TransferKind.CHUNKED) {
46154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      conn.setChunkedStreamingMode(-1);
46254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
46354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      conn.setFixedLengthStreamingMode(n);
46454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
46554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    OutputStream out = conn.getOutputStream();
46654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (writeKind == WriteKind.BYTE_BY_BYTE) {
46754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      for (int i = 0; i < n; ++i) {
46854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        out.write('x');
46954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
47054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
47154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      byte[] buf = new byte[writeKind == WriteKind.SMALL_BUFFERS ? 256 : 64 * 1024];
47254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      Arrays.fill(buf, (byte) 'x');
47354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      for (int i = 0; i < n; i += buf.length) {
47454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        out.write(buf, 0, Math.min(buf.length, n - i));
47554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
47654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
47754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    out.close();
47854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(200, conn.getResponseCode());
47954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
48054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(n, request.getBodySize());
48154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (uploadKind == TransferKind.CHUNKED) {
48254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertTrue(request.getChunkSizes().size() > 0);
48354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
48454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertTrue(request.getChunkSizes().isEmpty());
48554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
48654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
48754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
48854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getResponseCodeNoResponseBody() throws Exception {
48954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().addHeader("abc: def"));
49054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
49154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = server.getUrl("/");
49254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection conn = client.open(url);
49354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    conn.setDoInput(false);
49454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("def", conn.getHeaderField("abc"));
49554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(200, conn.getResponseCode());
49654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
49754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      conn.getInputStream();
49854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
49954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (ProtocolException expected) {
50054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
50154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
50254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
50354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttps() throws Exception {
50471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
50554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
50654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
507e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
508e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
5093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
51054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
51154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via HTTPS", connection);
51254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
51354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
51454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
51554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
51654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
5173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void inspectHandshakeThroughoutRequestLifecycle() throws Exception {
51871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
5193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse());
5203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
521e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
522e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
5233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
5243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpsURLConnection httpsConnection = (HttpsURLConnection) client.open(server.getUrl("/foo"));
5253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
5263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // Prior to calling connect(), getting the cipher suite is forbidden.
5273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    try {
5283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      httpsConnection.getCipherSuite();
5293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      fail();
5303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    } catch (IllegalStateException expected) {
5313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
5323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
5333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // Calling connect establishes a handshake...
5343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    httpsConnection.connect();
5353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertNotNull(httpsConnection.getCipherSuite());
5363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
5373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // ...which remains after we read the response body...
5383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("", httpsConnection);
5393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertNotNull(httpsConnection.getCipherSuite());
5403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
5413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // ...and after we disconnect.
5423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    httpsConnection.disconnect();
5433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertNotNull(httpsConnection.getCipherSuite());
5443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
5453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
54654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpsReusingConnections() throws IOException, InterruptedException {
54771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
54854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
54954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("another response via HTTPS"));
55054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
55154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // The pool will only reuse sockets if the SSL socket factories are the same.
55254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    SSLSocketFactory clientSocketFactory = sslContext.getSocketFactory();
55354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
55454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
555e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(clientSocketFactory);
556e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(hostnameVerifier);
5573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
55854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via HTTPS", connection);
55954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
56054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection = client.open(server.getUrl("/"));
56154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("another response via HTTPS", connection);
56254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
56354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
56454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, server.takeRequest().getSequenceNumber());
56554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
56654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
56754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpsReusingConnectionsDifferentFactories()
56854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throws IOException, InterruptedException {
56971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
57054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
57154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("another response via HTTPS"));
57254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
57354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // install a custom SSL socket factory so the server can be authorized
574e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
575e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
57654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection connection1 = client.open(server.getUrl("/"));
57754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via HTTPS", connection1);
57854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
579e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(null);
58054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection connection2 = client.open(server.getUrl("/"));
58154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
58254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      readAscii(connection2.getInputStream(), Integer.MAX_VALUE);
58354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("without an SSL socket factory, the connection should fail");
58454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (SSLException expected) {
58554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
58654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
58754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
5887aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller  @Test public void connectViaHttpsWithSSLFallback() throws Exception {
58971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
59054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
59154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("this response comes via SSL"));
59254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
593e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    suppressTlsFallbackScsv(client.client());
594e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
5953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
59654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
59754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via SSL", connection);
59854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
59954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
60054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
6017aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    assertEquals(TlsVersion.TLS_1_0, request.getTlsVersion());
6027aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller  }
6037aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller
6047aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller  @Test public void connectViaHttpsWithSSLFallbackFailuresRecorded() throws Exception {
60571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
6067aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
6077aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
6087aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller
6097aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    suppressTlsFallbackScsv(client.client());
6107aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    Internal.instance.setNetwork(client.client(), new SingleInetAddressNetwork());
6117aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller
6127aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
6137aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    connection = client.open(server.getUrl("/foo"));
6147aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller
6157aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    try {
6167aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller      connection.getResponseCode();
61771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
61871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (IOException expected) {
61971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      assertEquals(1, expected.getSuppressed().length);
6207aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller    }
62154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
62254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
62354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
6243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * When a pooled connection fails, don't blame the route. Otherwise pooled
6253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * connection failures can cause unnecessary SSL fallbacks.
6263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   *
6273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * https://github.com/square/okhttp/issues/515
6283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
6293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void sslFallbackNotUsedWhenRecycledConnectionFails() throws Exception {
63071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
6313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse()
6323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setBody("abc")
6333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END));
6343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("def"));
6353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
636e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    suppressTlsFallbackScsv(client.client());
637e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
6383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
6393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("abc", client.open(server.getUrl("/")));
6403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("def", client.open(server.getUrl("/")));
6413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
642e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Set<TlsVersion> tlsVersions =
643e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        EnumSet.of(TlsVersion.TLS_1_0, TlsVersion.TLS_1_2); // v1.2 on OpenJDK 8.
644e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
6453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request1 = server.takeRequest();
646e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertTrue(tlsVersions.contains(request1.getTlsVersion()));
6473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
6483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request2 = server.takeRequest();
649e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertTrue(tlsVersions.contains(request2.getTlsVersion()));
6503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
6513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
6523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
65354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Verify that we don't retry connections on certificate verification errors.
65454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   *
65554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * http://code.google.com/p/android/issues/detail?id=13178
65654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
65754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpsToUntrustedServer() throws IOException, InterruptedException {
65871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
65954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse()); // unused
66054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
6613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
66254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
66354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getInputStream();
66454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
66554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (SSLHandshakeException expected) {
66654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertTrue(expected.getCause() instanceof CertificateException);
66754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
66854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.getRequestCount());
66954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
67054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
67154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaProxyUsingProxyArg() throws Exception {
67254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaProxy(ProxyConfig.CREATE_ARG);
67354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
67454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
67554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaProxyUsingProxySystemProperty() throws Exception {
67654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaProxy(ProxyConfig.PROXY_SYSTEM_PROPERTY);
67754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
67854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
67954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaProxyUsingHttpProxySystemProperty() throws Exception {
68054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaProxy(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
68154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
68254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
683c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller  // ANDROID-BEGIN: http://b/29983827
68454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testConnectViaProxy(ProxyConfig proxyConfig) throws Exception {
685c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller    testConnectViaProxy(proxyConfig, "http://android.com/foo", "android.com");
686c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller    testConnectViaProxy(proxyConfig, "http://android.com/", "android.com");
687c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller    testConnectViaProxy(proxyConfig, "http://android.com", "android.com");
688c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller    testConnectViaProxy(proxyConfig, "http://mms", "mms");
689c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller  }
690c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller
691c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller  private void testConnectViaProxy(ProxyConfig proxyConfig, String urlString, String expectedHost)
692c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller          throws Exception {
69354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse mockResponse = new MockResponse().setBody("this response comes via a proxy");
69454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(mockResponse);
69554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
696c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller    URL url = new URL(urlString);
69771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    connection = proxyConfig.connect(server, client, url);
69854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via a proxy", connection);
6993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertTrue(connection.usingProxy());
70054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
70171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    RecordedRequest request = server.takeRequest();
702c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller    assertEquals("GET " + urlString + " HTTP/1.1", request.getRequestLine());
703c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller    assertEquals(expectedHost, request.getHeader("Host"));
70454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
705c6817fbea3bc321e3816492c18f98c45895630f6Neil Fuller  // ANDROID-END: http://b/29983827
70654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
70771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void contentDisagreesWithContentLengthHeaderBodyTooLong() throws IOException {
70854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("abc\r\nYOU SHOULD NOT SEE THIS")
70954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .clearHeaders()
71054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Content-Length: 3"));
71154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("abc", client.open(server.getUrl("/")));
71254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
71354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
71471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void contentDisagreesWithContentLengthHeaderBodyTooShort() throws IOException {
71571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.enqueue(new MockResponse().setBody("abc")
71671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .setHeader("Content-Length", "5")
71771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END));
71871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
71971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      readAscii(client.open(server.getUrl("/")).getInputStream(), 5);
72071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
72171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (ProtocolException expected) {
72271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
72371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
72471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
725a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti  public void testConnectViaSocketFactory(boolean useHttps) throws IOException {
726a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    SocketFactory uselessSocketFactory = new SocketFactory() {
727a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      public Socket createSocket() { throw new IllegalArgumentException("useless"); }
728a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      public Socket createSocket(InetAddress host, int port) { return null; }
729a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
730a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti          int localPort) { return null; }
731a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      public Socket createSocket(String host, int port) { return null; }
732a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      public Socket createSocket(String host, int port, InetAddress localHost, int localPort) {
733a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti        return null;
734a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      }
735a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    };
736a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti
737a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    if (useHttps) {
73871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      server.useHttps(sslContext.getSocketFactory(), false);
739e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setSslSocketFactory(sslContext.getSocketFactory());
740e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setHostnameVerifier(new RecordingHostnameVerifier());
741a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    }
742a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti
743a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 OK"));
744a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti
745e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSocketFactory(uselessSocketFactory);
746a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    connection = client.open(server.getUrl("/"));
747a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    try {
748a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      connection.getResponseCode();
749a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti      fail();
750a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    } catch (IllegalArgumentException expected) {
751a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    }
752a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti
753e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSocketFactory(SocketFactory.getDefault());
754a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    connection = client.open(server.getUrl("/"));
755a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    assertEquals(200, connection.getResponseCode());
756a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti  }
757a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti
758a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti  @Test public void connectHttpViaSocketFactory() throws Exception {
759a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    testConnectViaSocketFactory(false);
760a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti  }
761a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti
762a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti  @Test public void connectHttpsViaSocketFactory() throws Exception {
763a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti    testConnectViaSocketFactory(true);
764a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti  }
765a83ddf194ffbae04ce536967efff0ec72df70e10Lorenzo Colitti
76671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void contentDisagreesWithChunkedHeaderBodyTooLong() throws IOException {
76754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse mockResponse = new MockResponse();
76854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    mockResponse.setChunkedBody("abc", 3);
769e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Buffer buffer = mockResponse.getBody();
770e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    buffer.writeUtf8("\r\nYOU SHOULD NOT SEE THIS");
771e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    mockResponse.setBody(buffer);
77254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    mockResponse.clearHeaders();
77354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    mockResponse.addHeader("Transfer-encoding: chunked");
77454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
77554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(mockResponse);
77654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
77754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("abc", client.open(server.getUrl("/")));
77854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
77954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
78071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void contentDisagreesWithChunkedHeaderBodyTooShort() throws IOException {
78171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    MockResponse mockResponse = new MockResponse();
78271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    mockResponse.setChunkedBody("abcde", 5);
78371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
78471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    Buffer truncatedBody = new Buffer();
78571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    Buffer fullBody = mockResponse.getBody();
78671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    truncatedBody.write(fullBody, fullBody.indexOf((byte) 'e'));
78771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    mockResponse.setBody(truncatedBody);
78871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
78971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    mockResponse.clearHeaders();
79071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    mockResponse.addHeader("Transfer-encoding: chunked");
79171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    mockResponse.setSocketPolicy(SocketPolicy.DISCONNECT_AT_END);
79271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
79371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.enqueue(mockResponse);
79471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
79571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
79671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      readAscii(client.open(server.getUrl("/")).getInputStream(), 5);
79771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
79871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (ProtocolException expected) {
79971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
80071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
80171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
80254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpProxyToHttpsUsingProxyArgWithNoProxy() throws Exception {
80354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaDirectProxyToHttps(ProxyConfig.NO_PROXY);
80454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
80554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
80654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpProxyToHttpsUsingHttpProxySystemProperty() throws Exception {
80754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // https should not use http proxy
80854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaDirectProxyToHttps(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
80954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
81054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
81154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testConnectViaDirectProxyToHttps(ProxyConfig proxyConfig) throws Exception {
81271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
81354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
81454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
81554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = server.getUrl("/foo");
816e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
817e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
81871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    connection = proxyConfig.connect(server, client, url);
81954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
82054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via HTTPS", connection);
82154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
82254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
82354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
82454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
82554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
82654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpProxyToHttpsUsingProxyArg() throws Exception {
82754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaHttpProxyToHttps(ProxyConfig.CREATE_ARG);
82854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
82954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
83054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
83154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * We weren't honoring all of the appropriate proxy system properties when
83254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * connecting via HTTPS. http://b/3097518
83354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
83454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpProxyToHttpsUsingProxySystemProperty() throws Exception {
83554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaHttpProxyToHttps(ProxyConfig.PROXY_SYSTEM_PROPERTY);
83654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
83754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
83854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpProxyToHttpsUsingHttpsProxySystemProperty() throws Exception {
83954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testConnectViaHttpProxyToHttps(ProxyConfig.HTTPS_PROXY_SYSTEM_PROPERTY);
84054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
84154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
84254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
84354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * We were verifying the wrong hostname when connecting to an HTTPS site
84454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * through a proxy. http://b/3097277
84554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
84654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception {
84754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
84854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
84971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), true);
85054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(
85154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        new MockResponse().setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END).clearHeaders());
85254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("this response comes via a secure proxy"));
85354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
85454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = new URL("https://android.com/foo");
855e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
856e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(hostnameVerifier);
85771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    connection = proxyConfig.connect(server, client, url);
85854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
85954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via a secure proxy", connection);
86054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
86154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest connect = server.takeRequest();
86254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("Connect line failure on proxy", "CONNECT android.com:443 HTTP/1.1",
86354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        connect.getRequestLine());
864e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("android.com", connect.getHeader("Host"));
86554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
86654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest get = server.takeRequest();
86754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", get.getRequestLine());
868e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("android.com", get.getHeader("Host"));
86954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(Arrays.asList("verify android.com"), hostnameVerifier.calls);
87054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
87154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
872e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  /** Tolerate bad https proxy response when using HttpResponseCache. Android bug 6754912. */
87354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache() throws Exception {
87454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    initResponseCache();
87554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
87671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), true);
877e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    // The inclusion of a body in the response to a CONNECT is key to reproducing b/6754912.
878e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    MockResponse badProxyResponse = new MockResponse()
87954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
88054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("bogus proxy connect response content");
881e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(badProxyResponse);
882e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("response"));
88354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
884e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    // Configure a single IP address for the host and a single configuration, so we only need one
885e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    // failure to fail permanently.
886e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Internal.instance.setNetwork(client.client(), new SingleInetAddressNetwork());
887e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
888e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setConnectionSpecs(Util.immutableList(ConnectionSpec.MODERN_TLS));
889e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
89071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    client.client().setProxy(server.toProxyAddress());
89154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
89254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = new URL("https://android.com/foo");
8933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(url);
894e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("response", connection);
89554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
89654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest connect = server.takeRequest();
897e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("CONNECT android.com:443 HTTP/1.1", connect.getRequestLine());
898e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("android.com", connect.getHeader("Host"));
89954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
90054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
90154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void initResponseCache() throws IOException {
902e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    cache = new Cache(tempDir.getRoot(), Integer.MAX_VALUE);
903e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setCache(cache);
90454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
90554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
90654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** Test which headers are sent unencrypted to the HTTP proxy. */
90754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void proxyConnectIncludesProxyHeadersOnly()
90854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throws IOException, InterruptedException {
90954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
91054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
91171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), true);
91254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(
91354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        new MockResponse().setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END).clearHeaders());
91454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("encrypted response from the origin server"));
915e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
91671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    client.client().setProxy(server.toProxyAddress());
91754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
91854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = new URL("https://android.com/foo");
919e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
920e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(hostnameVerifier);
9213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(url);
92254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.addRequestProperty("Private", "Secret");
92354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.addRequestProperty("Proxy-Authorization", "bar");
92454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.addRequestProperty("User-Agent", "baz");
92554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("encrypted response from the origin server", connection);
92654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
92754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest connect = server.takeRequest();
928e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(connect.getHeader("Private"));
929e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("bar", connect.getHeader("Proxy-Authorization"));
930e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("baz", connect.getHeader("User-Agent"));
931e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("android.com", connect.getHeader("Host"));
932e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("Keep-Alive", connect.getHeader("Proxy-Connection"));
93354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
93454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest get = server.takeRequest();
935e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("Secret", get.getHeader("Private"));
93654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(Arrays.asList("verify android.com"), hostnameVerifier.calls);
93754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
93854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
93954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void proxyAuthenticateOnConnect() throws Exception {
94054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    Authenticator.setDefault(new RecordingAuthenticator());
94171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), true);
94254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(407)
94354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Proxy-Authenticate: Basic realm=\"localhost\""));
94454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(
94554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        new MockResponse().setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END).clearHeaders());
94654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("A"));
947e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
94871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    client.client().setProxy(server.toProxyAddress());
94954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
95054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = new URL("https://android.com/foo");
951e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
952e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
9533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(url);
95454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("A", connection);
95554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
95654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest connect1 = server.takeRequest();
95754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("CONNECT android.com:443 HTTP/1.1", connect1.getRequestLine());
958e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(connect1.getHeader("Proxy-Authorization"));
95954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
96054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest connect2 = server.takeRequest();
96154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("CONNECT android.com:443 HTTP/1.1", connect2.getRequestLine());
962e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS,
963e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        connect2.getHeader("Proxy-Authorization"));
96454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
96554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest get = server.takeRequest();
96654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", get.getRequestLine());
967e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(get.getHeader("Proxy-Authorization"));
96854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
96954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
97054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // Don't disconnect after building a tunnel with CONNECT
97154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // http://code.google.com/p/android/issues/detail?id=37221
97254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void proxyWithConnectionClose() throws IOException {
97371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), true);
97454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(
97554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        new MockResponse().setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END).clearHeaders());
97654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("this response comes via a proxy"));
977e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
97871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    client.client().setProxy(server.toProxyAddress());
97954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
98054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = new URL("https://android.com/foo");
981e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
982e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
9833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(url);
98454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setRequestProperty("Connection", "close");
98554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
98654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("this response comes via a proxy", connection);
98754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
98854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
98954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void proxyWithConnectionReuse() throws IOException {
99054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    SSLSocketFactory socketFactory = sslContext.getSocketFactory();
99154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
99254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
99371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(socketFactory, true);
99454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(
99554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        new MockResponse().setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END).clearHeaders());
99654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("response 1"));
99754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("response 2"));
998e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
99971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    client.client().setProxy(server.toProxyAddress());
100054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
100154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = new URL("https://android.com/foo");
1002e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(socketFactory);
1003e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(hostnameVerifier);
100454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("response 1", client.open(url));
100554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("response 2", client.open(url));
100654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
100754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
100854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void disconnectedConnection() throws IOException {
100987ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson    server.enqueue(new MockResponse()
101087ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson        .throttleBody(2, 100, TimeUnit.MILLISECONDS)
101187ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson        .setBody("ABCD"));
101254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
10133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
101454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in = connection.getInputStream();
101554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals('A', (char) in.read());
101654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.disconnect();
101754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
101887ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson      // Reading 'B' may succeed if it's buffered.
101987ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson      in.read();
102087ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson
102187ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson      // But 'C' shouldn't be buffered (the response is throttled) and this should fail.
102254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      in.read();
102354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail("Expected a connection closed exception");
102454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
102554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
102654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
102754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
102854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void disconnectBeforeConnect() throws IOException {
102954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("A"));
103054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
10313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
103254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.disconnect();
103354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("A", connection);
103454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(200, connection.getResponseCode());
103554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
103654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
103754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @SuppressWarnings("deprecation") @Test public void defaultRequestProperty() throws Exception {
103854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection.setDefaultRequestProperty("X-testSetDefaultRequestProperty", "A");
103954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertNull(URLConnection.getDefaultRequestProperty("X-setDefaultRequestProperty"));
104054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
104154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
104254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
104354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Reads {@code count} characters from the stream. If the stream is
104454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * exhausted before {@code count} characters can be read, the remaining
104554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * characters are returned and the stream is closed.
104654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
104754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private String readAscii(InputStream in, int count) throws IOException {
104854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    StringBuilder result = new StringBuilder();
104954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    for (int i = 0; i < count; i++) {
105054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      int value = in.read();
105154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      if (value == -1) {
1052c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath        in.close();
105354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        break;
105454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
105554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      result.append((char) value);
105654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
105754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return result.toString();
105854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
105954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
106054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void markAndResetWithContentLengthHeader() throws IOException {
106154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testMarkAndReset(TransferKind.FIXED_LENGTH);
106254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
106354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
106454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void markAndResetWithChunkedEncoding() throws IOException {
106554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testMarkAndReset(TransferKind.CHUNKED);
106654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
106754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
106854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void markAndResetWithNoLengthHeaders() throws IOException {
106954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testMarkAndReset(TransferKind.END_OF_STREAM);
107054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
107154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
107254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testMarkAndReset(TransferKind transferKind) throws IOException {
107354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse();
107454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transferKind.setBody(response, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1024);
107554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
107654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
107754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
107854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in = client.open(server.getUrl("/")).getInputStream();
107954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertFalse("This implementation claims to support mark().", in.markSupported());
108054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    in.mark(5);
108154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("ABCDE", readAscii(in, 5));
108254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
108354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      in.reset();
108454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
108554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
108654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
108754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("FGHIJKLMNOPQRSTUVWXYZ", readAscii(in, Integer.MAX_VALUE));
108854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABCDEFGHIJKLMNOPQRSTUVWXYZ", client.open(server.getUrl("/")));
108954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
109054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
109154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
109254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * We've had a bug where we forget the HTTP response when we see response
109354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * code 401. This causes a new HTTP request to be issued for every call into
109454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * the URLConnection.
109554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
109654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void unauthorizedResponseHandling() throws IOException {
109754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse().addHeader("WWW-Authenticate: challenge")
109854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setResponseCode(401) // UNAUTHORIZED
109954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("Unauthorized");
110054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
110154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
110254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
110354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
110454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = server.getUrl("/");
110554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection conn = client.open(url);
110654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
110754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(401, conn.getResponseCode());
110854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(401, conn.getResponseCode());
110954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(401, conn.getResponseCode());
111054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, server.getRequestCount());
111154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
111254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
111354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void nonHexChunkSize() throws IOException {
111454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("5\r\nABCDE\r\nG\r\nFGHIJKLMNOPQRSTU\r\n0\r\n\r\n")
111554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .clearHeaders()
111654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Transfer-encoding: chunked"));
111754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
111854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
111954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
112054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      readAscii(connection.getInputStream(), Integer.MAX_VALUE);
112154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
112254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException e) {
112354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
112454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
112554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1126a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller  @Test public void malformedChunkSize() throws IOException {
1127a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    server.enqueue(new MockResponse().setBody("5:x\r\nABCDE\r\n0\r\n\r\n")
1128a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        .clearHeaders()
1129a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        .addHeader("Transfer-encoding: chunked"));
1130a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller
1131a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    URLConnection connection = client.open(server.getUrl("/"));
1132a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    try {
1133a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller      readAscii(connection.getInputStream(), Integer.MAX_VALUE);
1134a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller      fail();
1135a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    } catch (IOException e) {
1136a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    }
1137a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller  }
1138a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller
1139a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller  @Test public void extensionAfterChunkSize() throws IOException {
1140a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    server.enqueue(new MockResponse().setBody("5;x\r\nABCDE\r\n0\r\n\r\n")
1141a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        .clearHeaders()
1142a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        .addHeader("Transfer-encoding: chunked"));
1143a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller
1144a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    HttpURLConnection connection = client.open(server.getUrl("/"));
1145a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    assertContent("ABCDE", connection);
1146a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller  }
1147a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller
114854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void missingChunkBody() throws IOException {
114954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("5")
115054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .clearHeaders()
115154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Transfer-encoding: chunked")
115254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setSocketPolicy(DISCONNECT_AT_END));
115354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
115454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
115554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
115654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      readAscii(connection.getInputStream(), Integer.MAX_VALUE);
115754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
115854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException e) {
115954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
116054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
116154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
116254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
116354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * This test checks whether connections are gzipped by default. This
116454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * behavior in not required by the API, so a failure of this test does not
116554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * imply a bug in the implementation.
116654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
116754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void gzipEncodingEnabledByDefault() throws IOException, InterruptedException {
1168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
1169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody(gzip("ABCABCABC"))
117054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Content-Encoding: gzip"));
117154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
117254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
117354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("ABCABCABC", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
117454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertNull(connection.getContentEncoding());
117554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(-1, connection.getContentLength());
117654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
117754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
1178e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("gzip", request.getHeader("Accept-Encoding"));
117954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
118054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
118154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void clientConfiguredGzipContentEncoding() throws Exception {
1182e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Buffer bodyBytes = gzip("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
118354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse()
118454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody(bodyBytes)
118554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Content-Encoding: gzip"));
118654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
118754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
118854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.addRequestProperty("Accept-Encoding", "gzip");
118954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream gunzippedIn = new GZIPInputStream(connection.getInputStream());
119054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", readAscii(gunzippedIn, Integer.MAX_VALUE));
1191e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(bodyBytes.size(), connection.getContentLength());
119254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
119354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
1194e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("gzip", request.getHeader("Accept-Encoding"));
119554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
119654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
119754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void gzipAndConnectionReuseWithFixedLength() throws Exception {
119854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.FIXED_LENGTH, false);
119954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
120054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
120154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void gzipAndConnectionReuseWithChunkedEncoding() throws Exception {
120254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.CHUNKED, false);
120354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
120454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
120554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void gzipAndConnectionReuseWithFixedLengthAndTls() throws Exception {
120654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.FIXED_LENGTH, true);
120754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
120854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
120954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void gzipAndConnectionReuseWithChunkedEncodingAndTls() throws Exception {
121054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.CHUNKED, true);
121154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
121254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
121354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void clientConfiguredCustomContentEncoding() throws Exception {
121454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("ABCDE").addHeader("Content-Encoding: custom"));
121554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
121654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
121754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.addRequestProperty("Accept-Encoding", "custom");
121854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("ABCDE", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
121954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
122054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
1221e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("custom", request.getHeader("Accept-Encoding"));
122254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
122354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
122454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
122554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Test a bug where gzip input streams weren't exhausting the input stream,
122654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * which corrupted the request that followed or prevented connection reuse.
122754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * http://code.google.com/p/android/issues/detail?id=7059
122854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * http://code.google.com/p/android/issues/detail?id=38817
122954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
123054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind transferKind,
123154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      boolean tls) throws Exception {
123254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (tls) {
123354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      SSLSocketFactory socketFactory = sslContext.getSocketFactory();
123454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
123571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      server.useHttps(socketFactory, false);
1236e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setSslSocketFactory(socketFactory);
1237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setHostnameVerifier(hostnameVerifier);
123854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
123954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
124054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse responseOne = new MockResponse();
124154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    responseOne.addHeader("Content-Encoding: gzip");
1242e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    transferKind.setBody(responseOne, gzip("one (gzipped)"), 5);
124354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(responseOne);
124454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse responseTwo = new MockResponse();
124554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transferKind.setBody(responseTwo, "two (identity)", 5);
124654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(responseTwo);
124754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
124854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection connection1 = client.open(server.getUrl("/"));
124954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection1.addRequestProperty("Accept-Encoding", "gzip");
125054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream gunzippedIn = new GZIPInputStream(connection1.getInputStream());
125154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("one (gzipped)", readAscii(gunzippedIn, Integer.MAX_VALUE));
125254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
125354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
125454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection connection2 = client.open(server.getUrl("/"));
125554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("two (identity)", readAscii(connection2.getInputStream(), Integer.MAX_VALUE));
125654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, server.takeRequest().getSequenceNumber());
125754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
125854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1259c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  @Test public void transparentGzipWorksAfterExceptionRecovery() throws Exception {
1260c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    server.enqueue(new MockResponse()
1261c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        .setBody("a")
1262c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        .setSocketPolicy(SHUTDOWN_INPUT_AT_END));
1263c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    server.enqueue(new MockResponse()
1264c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        .addHeader("Content-Encoding: gzip")
1265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody(gzip("b")));
1266c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
1267c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    // Seed the pool with a bad connection.
1268c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    assertContent("a", client.open(server.getUrl("/")));
1269c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
1270c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    // This connection will need to be recovered. When it is, transparent gzip should still work!
1271c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    assertContent("b", client.open(server.getUrl("/")));
1272c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
1273c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    assertEquals(0, server.takeRequest().getSequenceNumber());
1274c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    assertEquals(0, server.takeRequest().getSequenceNumber()); // Connection is not pooled.
1275c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  }
1276c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
1277c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  @Test public void endOfStreamResponseIsNotPooled() throws Exception {
1278c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    server.enqueue(new MockResponse()
1279c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        .setBody("{}")
1280c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        .clearHeaders()
1281c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller        .setSocketPolicy(DISCONNECT_AT_END));
1282c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
1283c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    ConnectionPool pool = ConnectionPool.getDefault();
1284c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    pool.evictAll();
1285e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setConnectionPool(pool);
1286c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
1287c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    HttpURLConnection connection = client.open(server.getUrl("/"));
1288c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller    assertContent("{}", connection);
1289e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(0, client.client().getConnectionPool().getConnectionCount());
1290c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller  }
1291c6bd683320121544811f481709b3fdbcbe9b3866Neil Fuller
129254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void earlyDisconnectDoesntHarmPoolingWithChunkedEncoding() throws Exception {
129354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testEarlyDisconnectDoesntHarmPooling(TransferKind.CHUNKED);
129454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
129554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
129654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void earlyDisconnectDoesntHarmPoolingWithFixedLengthEncoding() throws Exception {
129754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testEarlyDisconnectDoesntHarmPooling(TransferKind.FIXED_LENGTH);
129854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
129954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
130054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testEarlyDisconnectDoesntHarmPooling(TransferKind transferKind) throws Exception {
130154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response1 = new MockResponse();
130254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transferKind.setBody(response1, "ABCDEFGHIJK", 1024);
130354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response1);
130454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
130554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response2 = new MockResponse();
130654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transferKind.setBody(response2, "LMNOPQRSTUV", 1024);
130754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response2);
130854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
13093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection1 = client.open(server.getUrl("/"));
131054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in1 = connection1.getInputStream();
131154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("ABCDE", readAscii(in1, 5));
131287ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson    in1.close();
13133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection1.disconnect();
131454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
131554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection connection2 = client.open(server.getUrl("/"));
131654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in2 = connection2.getInputStream();
131754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("LMNOP", readAscii(in2, 5));
131887ed7244fb53ae2bac9f23c033bbd5f23ac269f8Jesse Wilson    in2.close();
13193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection2.disconnect();
132054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
132154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
132254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection is pooled!
132354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
132454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
13253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void streamDiscardingIsTimely() throws Exception {
13263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // This response takes at least a full second to serve: 10,000 bytes served 100 bytes at a time.
13273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse()
1328e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody(new Buffer().write(new byte[10000]))
13293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .throttleBody(100, 10, MILLISECONDS));
13303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("A"));
13313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
13323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    long startNanos = System.nanoTime();
13333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    URLConnection connection1 = client.open(server.getUrl("/"));
13343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    InputStream in = connection1.getInputStream();
13353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    in.close();
13363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    long elapsedNanos = System.nanoTime() - startNanos;
13373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    long elapsedMillis = NANOSECONDS.toMillis(elapsedNanos);
13383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
13393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // If we're working correctly, this should be greater than 100ms, but less than double that.
13403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // Previously we had a bug where we would download the entire response body as long as no
13413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // individual read took longer than 100ms.
13423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertTrue(String.format("Time to close: %sms", elapsedMillis), elapsedMillis < 500);
13433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
13443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // Do another request to confirm that the discarded connection was not pooled.
13453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", client.open(server.getUrl("/")));
13463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
13473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, server.takeRequest().getSequenceNumber());
13483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, server.takeRequest().getSequenceNumber()); // Connection is not pooled.
13493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
13503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
135154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void setChunkedStreamingMode() throws IOException, InterruptedException {
135254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
135354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
13543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    String body = "ABCDEFGHIJKLMNOPQ";
13553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
13563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setChunkedStreamingMode(0); // OkHttp does not honor specific chunk sizes.
13573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
13583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    OutputStream outputStream = connection.getOutputStream();
13593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    outputStream.write(body.getBytes("US-ASCII"));
13603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(200, connection.getResponseCode());
136154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
136254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
1363e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(body, request.getBody().readUtf8());
13643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(Arrays.asList(body.length()), request.getChunkSizes());
136554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
136654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
136754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void authenticateWithFixedLengthStreaming() throws Exception {
136854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testAuthenticateWithStreamingPost(StreamingMode.FIXED_LENGTH);
136954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
137054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
137154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void authenticateWithChunkedStreaming() throws Exception {
137254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testAuthenticateWithStreamingPost(StreamingMode.CHUNKED);
137354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
137454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
137554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testAuthenticateWithStreamingPost(StreamingMode streamingMode) throws Exception {
137654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(401)
137754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
137854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("Please authenticate.");
137954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
138054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
138154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    Authenticator.setDefault(new RecordingAuthenticator());
13823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
138354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
138454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    byte[] requestBody = { 'A', 'B', 'C', 'D' };
138554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (streamingMode == StreamingMode.FIXED_LENGTH) {
138654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setFixedLengthStreamingMode(requestBody.length);
138754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (streamingMode == StreamingMode.CHUNKED) {
138854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setChunkedStreamingMode(0);
138954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
139054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    OutputStream outputStream = connection.getOutputStream();
139154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.write(requestBody);
139254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.close();
139354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
139454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getInputStream();
139554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
139654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (HttpRetryException expected) {
139754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
139854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
139954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // no authorization header for the request...
140054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
1401e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("Authorization"));
1402e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("ABCD", request.getBody().readUtf8());
1403e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
1404e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1405e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void postBodyRetransmittedAfterAuthorizationFail() throws Exception {
1406e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    postBodyRetransmittedAfterAuthorizationFail("abc");
1407e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
1408e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1409e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void postBodyRetransmittedAfterAuthorizationFail_SPDY_3() throws Exception {
1410e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.SPDY_3);
1411e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    postBodyRetransmittedAfterAuthorizationFail("abc");
1412e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
1413e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1414e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void postBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception {
1415e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.HTTP_2);
1416e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    postBodyRetransmittedAfterAuthorizationFail("abc");
1417e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
1418e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1419e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  /** Don't explode when resending an empty post. https://github.com/square/okhttp/issues/1131 */
1420e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail() throws Exception {
1421e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    postBodyRetransmittedAfterAuthorizationFail("");
1422e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
1423e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1424e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_SPDY_3() throws Exception {
1425e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.SPDY_3);
1426e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    postBodyRetransmittedAfterAuthorizationFail("");
1427e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
1428e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1429e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception {
1430e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.HTTP_2);
1431e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    postBodyRetransmittedAfterAuthorizationFail("");
1432e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
1433e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1434e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exception {
1435e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setResponseCode(401));
1436e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse());
1437e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1438e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    String credential = Credentials.basic("jesse", "secret");
1439e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setAuthenticator(new RecordingOkAuthenticator(credential));
1440e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1441e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/"));
1442e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.setDoOutput(true);
1443e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    OutputStream outputStream = connection.getOutputStream();
1444e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    outputStream.write(body.getBytes("UTF-8"));
1445e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    outputStream.close();
1446e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(200, connection.getResponseCode());
1447e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1448e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest recordedRequest1 = server.takeRequest();
1449e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("POST", recordedRequest1.getMethod());
1450e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(body, recordedRequest1.getBody().readUtf8());
1451e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(recordedRequest1.getHeader("Authorization"));
1452e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1453e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest recordedRequest2 = server.takeRequest();
1454e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("POST", recordedRequest2.getMethod());
1455e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(body, recordedRequest2.getBody().readUtf8());
1456e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(credential, recordedRequest2.getHeader("Authorization"));
145754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
145854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
145954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void nonStandardAuthenticationScheme() throws Exception {
146054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    List<String> calls = authCallsForHeader("WWW-Authenticate: Foo");
146154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(Collections.<String>emptyList(), calls);
146254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
146354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
146454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void nonStandardAuthenticationSchemeWithRealm() throws Exception {
146554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    List<String> calls = authCallsForHeader("WWW-Authenticate: Foo realm=\"Bar\"");
1466166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    assertEquals(0, calls.size());
146754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
146854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
146954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // Digest auth is currently unsupported. Test that digest requests should fail reasonably.
147054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // http://code.google.com/p/android/issues/detail?id=11140
147154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void digestAuthentication() throws Exception {
147254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    List<String> calls = authCallsForHeader("WWW-Authenticate: Digest "
147354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        + "realm=\"testrealm@host.com\", qop=\"auth,auth-int\", "
147454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        + "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
147554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        + "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"");
1476166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    assertEquals(0, calls.size());
147754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
147854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
147954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void allAttributesSetInServerAuthenticationCallbacks() throws Exception {
148054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    List<String> calls = authCallsForHeader("WWW-Authenticate: Basic realm=\"Bar\"");
148154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, calls.size());
148254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = server.getUrl("/");
148354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    String call = calls.get(0);
148454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("host=" + url.getHost()));
148554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("port=" + url.getPort()));
1486e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertTrue(call, call.contains("site=" + url.getHost()));
148754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("url=" + url));
148854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("type=" + Authenticator.RequestorType.SERVER));
148954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("prompt=Bar"));
149054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("protocol=http"));
149154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.toLowerCase().contains("scheme=basic")); // lowercase for the RI.
149254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
149354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
149454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void allAttributesSetInProxyAuthenticationCallbacks() throws Exception {
149554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    List<String> calls = authCallsForHeader("Proxy-Authenticate: Basic realm=\"Bar\"");
149654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, calls.size());
149754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = server.getUrl("/");
149854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    String call = calls.get(0);
149954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("host=" + url.getHost()));
150054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("port=" + url.getPort()));
1501e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertTrue(call, call.contains("site=" + url.getHost()));
150254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("url=http://android.com"));
150354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("type=" + Authenticator.RequestorType.PROXY));
150454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("prompt=Bar"));
150554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.contains("protocol=http"));
150654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(call, call.toLowerCase().contains("scheme=basic")); // lowercase for the RI.
150754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
150854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
150954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private List<String> authCallsForHeader(String authHeader) throws IOException {
151054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    boolean proxy = authHeader.startsWith("Proxy-");
151154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    int responseCode = proxy ? 407 : 401;
151254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordingAuthenticator authenticator = new RecordingAuthenticator(null);
151354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    Authenticator.setDefault(authenticator);
151454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(responseCode)
151554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader(authHeader)
151654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("Please authenticate.");
151754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
151854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
151954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (proxy) {
152071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      client.client().setProxy(server.toProxyAddress());
152154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection = client.open(new URL("http://android.com"));
152254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else {
152354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection = client.open(server.getUrl("/"));
152454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
152554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(responseCode, connection.getResponseCode());
152654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    return authenticator.calls;
152754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
152854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
152954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void setValidRequestMethod() throws Exception {
153054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertValidRequestMethod("GET");
153154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertValidRequestMethod("DELETE");
153254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertValidRequestMethod("HEAD");
153354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertValidRequestMethod("OPTIONS");
153454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertValidRequestMethod("POST");
153554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertValidRequestMethod("PUT");
153654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertValidRequestMethod("TRACE");
15373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertValidRequestMethod("PATCH");
153854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
153954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
154054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void assertValidRequestMethod(String requestMethod) throws Exception {
15413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
154254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setRequestMethod(requestMethod);
154354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(requestMethod, connection.getRequestMethod());
154454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
154554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
154654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void setInvalidRequestMethodLowercase() throws Exception {
154754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertInvalidRequestMethod("get");
154854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
154954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
155054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void setInvalidRequestMethodConnect() throws Exception {
155154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertInvalidRequestMethod("CONNECT");
155254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
155354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
155454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void assertInvalidRequestMethod(String requestMethod) throws Exception {
15553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
155654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
155754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setRequestMethod(requestMethod);
155854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
155954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (ProtocolException expected) {
156054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
156154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
156254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
15633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void shoutcast() throws Exception {
15643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setStatus("ICY 200 OK")
15653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        // .addHeader("HTTP/1.0 200 OK")
15663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Accept-Ranges: none")
15673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Content-Type: audio/mpeg")
15683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-br:128")
15693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("ice-audio-info: bitrate=128;samplerate=44100;channels=2")
15703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-br:128")
15713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-description:Rock")
15723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-genre:riders")
15733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-name:A2RRock")
15743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-pub:1")
15753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-url:http://www.A2Rradio.com")
15763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Server: Icecast 2.3.3-kh8")
15773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Cache-Control: no-cache")
15783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Pragma: no-cache")
15793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Expires: Mon, 26 Jul 1997 05:00:00 GMT")
15803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("icy-metaint:16000")
15813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setBody("mp3 data"));
15823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
15833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(200, connection.getResponseCode());
15843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("OK", connection.getResponseMessage());
15853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("mp3 data", connection);
15863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
15873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
158854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void cannotSetNegativeFixedLengthStreamingMode() throws Exception {
15893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
159054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
159154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setFixedLengthStreamingMode(-2);
159254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
159354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalArgumentException expected) {
159454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
159554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
159654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
159754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void canSetNegativeChunkedStreamingMode() throws Exception {
15983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
159954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setChunkedStreamingMode(-2);
160054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
160154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
160254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void cannotSetFixedLengthStreamingModeAfterConnect() throws Exception {
160354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("A"));
16043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
160554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
160654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
160754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setFixedLengthStreamingMode(1);
160854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
160954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
161054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
161154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
161254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
161354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void cannotSetChunkedStreamingModeAfterConnect() throws Exception {
161454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("A"));
16153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
161654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
161754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
161854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setChunkedStreamingMode(1);
161954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
162054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
162154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
162254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
162354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
162454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void cannotSetFixedLengthStreamingModeAfterChunkedStreamingMode() throws Exception {
16253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
162654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setChunkedStreamingMode(1);
162754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
162854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setFixedLengthStreamingMode(1);
162954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
163054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
163154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
163254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
163354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
163454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void cannotSetChunkedStreamingModeAfterFixedLengthStreamingMode() throws Exception {
16353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
163654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setFixedLengthStreamingMode(1);
163754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
163854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setChunkedStreamingMode(1);
163954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
164054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
164154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
164254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
164354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
164454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void secureFixedLengthStreaming() throws Exception {
164554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testSecureStreamingPost(StreamingMode.FIXED_LENGTH);
164654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
164754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
164854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void secureChunkedStreaming() throws Exception {
164954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testSecureStreamingPost(StreamingMode.CHUNKED);
165054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
165154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
165254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
165354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Users have reported problems using HTTPS with streaming request bodies.
165454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * http://code.google.com/p/android/issues/detail?id=12860
165554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
165654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testSecureStreamingPost(StreamingMode streamingMode) throws Exception {
165771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
165854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("Success!"));
165954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1660e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
1661e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
16623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
166354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
166454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    byte[] requestBody = { 'A', 'B', 'C', 'D' };
166554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (streamingMode == StreamingMode.FIXED_LENGTH) {
166654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setFixedLengthStreamingMode(requestBody.length);
166754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (streamingMode == StreamingMode.CHUNKED) {
166854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setChunkedStreamingMode(0);
166954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
167054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    OutputStream outputStream = connection.getOutputStream();
167154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.write(requestBody);
167254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.close();
167354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("Success!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
167454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
167554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
167654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("POST / HTTP/1.1", request.getRequestLine());
167754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (streamingMode == StreamingMode.FIXED_LENGTH) {
167854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals(Collections.<Integer>emptyList(), request.getChunkSizes());
167954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (streamingMode == StreamingMode.CHUNKED) {
168054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals(Arrays.asList(4), request.getChunkSizes());
168154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
1682e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("ABCD", request.getBody().readUtf8());
168354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
168454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
168554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  enum StreamingMode {
168654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    FIXED_LENGTH, CHUNKED
168754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
168854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
168954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void authenticateWithPost() throws Exception {
169054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(401)
169154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
169254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("Please authenticate.");
169354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // fail auth three times...
169454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
169554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
169654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
169754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // ...then succeed the fourth time
169854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("Successful auth!"));
169954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
170054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    Authenticator.setDefault(new RecordingAuthenticator());
17013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
170254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
170354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    byte[] requestBody = { 'A', 'B', 'C', 'D' };
170454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    OutputStream outputStream = connection.getOutputStream();
170554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.write(requestBody);
170654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.close();
170754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
170854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
170954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // no authorization header for the first request...
171054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
1711e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("Authorization"));
171254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
171354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // ...but the three requests that follow include an authorization header
171454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    for (int i = 0; i < 3; i++) {
171554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      request = server.takeRequest();
171654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals("POST / HTTP/1.1", request.getRequestLine());
1717e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      assertEquals("Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS,
1718e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          request.getHeader("Authorization"));
1719e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      assertEquals("ABCD", request.getBody().readUtf8());
172054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
172154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
172254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
172354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void authenticateWithGet() throws Exception {
172454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(401)
172554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
172654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("Please authenticate.");
172754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // fail auth three times...
172854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
172954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
173054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(pleaseAuthenticate);
173154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // ...then succeed the fourth time
173254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("Successful auth!"));
173354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
173454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    Authenticator.setDefault(new RecordingAuthenticator());
17353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
173654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
173754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
173854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // no authorization header for the first request...
173954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
1740e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("Authorization"));
174154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
174254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // ...but the three requests that follow requests include an authorization header
174354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    for (int i = 0; i < 3; i++) {
174454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      request = server.takeRequest();
174554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals("GET / HTTP/1.1", request.getRequestLine());
1746e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      assertEquals("Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS,
1747e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          request.getHeader("Authorization"));
174854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
174954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
175054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1751f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller  /** https://code.google.com/p/android/issues/detail?id=74026 */
1752f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller  @Test public void authenticateWithGetAndTransparentGzip() throws Exception {
1753f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(401)
1754f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller        .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
1755f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller        .setBody("Please authenticate.");
1756f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    // fail auth three times...
1757f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    server.enqueue(pleaseAuthenticate);
1758f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    server.enqueue(pleaseAuthenticate);
1759f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    server.enqueue(pleaseAuthenticate);
1760f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    // ...then succeed the fourth time
1761f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    MockResponse successfulResponse = new MockResponse()
1762f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller        .addHeader("Content-Encoding", "gzip")
1763e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody(gzip("Successful auth!"));
1764f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    server.enqueue(successfulResponse);
1765f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller
1766f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    Authenticator.setDefault(new RecordingAuthenticator());
1767f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    connection = client.open(server.getUrl("/"));
1768f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
1769f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller
1770f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    // no authorization header for the first request...
1771f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    RecordedRequest request = server.takeRequest();
1772e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(request.getHeader("Authorization"));
1773f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller
1774f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    // ...but the three requests that follow requests include an authorization header
1775f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    for (int i = 0; i < 3; i++) {
1776f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller      request = server.takeRequest();
1777f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller      assertEquals("GET / HTTP/1.1", request.getRequestLine());
1778e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      assertEquals("Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS,
1779e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          request.getHeader("Authorization"));
1780f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    }
1781f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller  }
1782f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller
1783166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath  /** https://github.com/square/okhttp/issues/342 */
1784166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath  @Test public void authenticateRealmUppercase() throws Exception {
1785166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    server.enqueue(new MockResponse().setResponseCode(401)
1786166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath        .addHeader("wWw-aUtHeNtIcAtE: bAsIc rEaLm=\"pRoTeCtEd aReA\"")
1787166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath        .setBody("Please authenticate."));
1788166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    server.enqueue(new MockResponse().setBody("Successful auth!"));
1789166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath
1790166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    Authenticator.setDefault(new RecordingAuthenticator());
17913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
1792166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
1793166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath  }
1794166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath
179554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void redirectedWithChunkedEncoding() throws Exception {
179654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testRedirected(TransferKind.CHUNKED, true);
179754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
179854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
179954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void redirectedWithContentLengthHeader() throws Exception {
180054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testRedirected(TransferKind.FIXED_LENGTH, true);
180154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
180254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
180354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void redirectedWithNoLengthHeaders() throws Exception {
180454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testRedirected(TransferKind.END_OF_STREAM, false);
180554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
180654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
180754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testRedirected(TransferKind transferKind, boolean reuse) throws Exception {
180854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
180954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: /foo");
181054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transferKind.setBody(response, "This page has moved!", 10);
181154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
181254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("This is the new location!"));
181354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
181454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
181554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("This is the new location!",
181654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        readAscii(connection.getInputStream(), Integer.MAX_VALUE));
181754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
181854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest first = server.takeRequest();
181954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET / HTTP/1.1", first.getRequestLine());
182054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest retry = server.takeRequest();
182154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", retry.getRequestLine());
182254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (reuse) {
182354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals("Expected connection reuse", 1, retry.getSequenceNumber());
182454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
182554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
182654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
182754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void redirectedOnHttps() throws IOException, InterruptedException {
182871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
182954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
183054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: /foo")
183154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("This page has moved!"));
183254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("This is the new location!"));
183354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1834e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
1835e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
18363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
183754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("This is the new location!",
183854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        readAscii(connection.getInputStream(), Integer.MAX_VALUE));
183954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
184054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest first = server.takeRequest();
184154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET / HTTP/1.1", first.getRequestLine());
184254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest retry = server.takeRequest();
184354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", retry.getRequestLine());
184454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("Expected connection reuse", 1, retry.getSequenceNumber());
184554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
184654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
184754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void notRedirectedFromHttpsToHttp() throws IOException, InterruptedException {
184871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
184954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
185054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: http://anyhost/foo")
185154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("This page has moved!"));
185254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1853e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setFollowSslRedirects(false);
1854e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
1855e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
18563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
185754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("This page has moved!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
185854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
185954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
186054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void notRedirectedFromHttpToHttps() throws IOException, InterruptedException {
186154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
186254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: https://anyhost/foo")
186354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("This page has moved!"));
186454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1865e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setFollowSslRedirects(false);
18663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
186754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("This page has moved!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
186854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
186954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
18707407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  @Test public void redirectedFromHttpsToHttpFollowingProtocolRedirects() throws Exception {
18717407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    server2.enqueue(new MockResponse().setBody("This is insecure HTTP!"));
18727407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
187371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
18747407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
18757407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        .addHeader("Location: " + server2.getUrl("/"))
18767407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        .setBody("This page has moved!"));
18777407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
1878e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
1879e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
1880e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setFollowSslRedirects(true);
18817407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    HttpsURLConnection connection = (HttpsURLConnection) client.open(server.getUrl("/"));
18827407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertContent("This is insecure HTTP!", connection);
18837407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertNull(connection.getCipherSuite());
18847407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertNull(connection.getLocalCertificates());
18857407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertNull(connection.getServerCertificates());
18867407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertNull(connection.getPeerPrincipal());
18877407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertNull(connection.getLocalPrincipal());
18887407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  }
18897407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
18907407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  @Test public void redirectedFromHttpToHttpsFollowingProtocolRedirects() throws Exception {
189171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server2.useHttps(sslContext.getSocketFactory(), false);
18927407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    server2.enqueue(new MockResponse().setBody("This is secure HTTPS!"));
18937407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
18947407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
18957407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        .addHeader("Location: " + server2.getUrl("/"))
18967407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        .setBody("This page has moved!"));
18977407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
1898e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
1899e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
1900e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setFollowSslRedirects(true);
19013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
19027407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertContent("This is secure HTTPS!", connection);
19037407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertFalse(connection instanceof HttpsURLConnection);
19047407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  }
19057407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
190654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void redirectToAnotherOriginServer() throws Exception {
19077407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    redirectToAnotherOriginServer(false);
19087407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  }
19097407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
19107407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  @Test public void redirectToAnotherOriginServerWithHttps() throws Exception {
19117407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    redirectToAnotherOriginServer(true);
19127407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  }
19137407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
19147407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  private void redirectToAnotherOriginServer(boolean https) throws Exception {
19157407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    if (https) {
191671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      server.useHttps(sslContext.getSocketFactory(), false);
191771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      server2.useHttps(sslContext.getSocketFactory(), false);
191871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      server2.setProtocolNegotiationEnabled(false);
1919e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setSslSocketFactory(sslContext.getSocketFactory());
1920e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setHostnameVerifier(new RecordingHostnameVerifier());
19217407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    }
19227407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
192354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server2.enqueue(new MockResponse().setBody("This is the 2nd server!"));
19247407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    server2.enqueue(new MockResponse().setBody("This is the 2nd server, again!"));
192554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
192654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
192754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: " + server2.getUrl("/").toString())
192854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("This page has moved!"));
192954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("This is the first server again!"));
193054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
19313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
19327407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertContent("This is the 2nd server!", connection);
193354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(server2.getUrl("/"), connection.getURL());
193454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
193554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // make sure the first server was careful to recycle the connection
19367407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertContent("This is the first server again!", client.open(server.getUrl("/")));
19377407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertContent("This is the 2nd server, again!", client.open(server2.getUrl("/")));
19387407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
193971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    String server1Host = server.getHostName() + ":" + server.getPort();
194071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    String server2Host = server2.getHostName() + ":" + server2.getPort();
1941e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(server1Host, server.takeRequest().getHeader("Host"));
1942e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(server2Host, server2.takeRequest().getHeader("Host"));
19437407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertEquals("Expected connection reuse", 1, server.takeRequest().getSequenceNumber());
19447407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertEquals("Expected connection reuse", 1, server2.takeRequest().getSequenceNumber());
19457407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  }
19467407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
19477407d6984ce69693097befc9b72609a8156463bbNarayan Kamath  @Test public void redirectWithProxySelector() throws Exception {
19487407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    final List<URI> proxySelectionRequests = new ArrayList<URI>();
1949e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setProxySelector(new ProxySelector() {
19507407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      @Override public List<Proxy> select(URI uri) {
19517407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        proxySelectionRequests.add(uri);
195271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        MockWebServer proxyServer = (uri.getPort() == server.getPort())
195371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller            ? server
195471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller            : server2;
19557407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        return Arrays.asList(proxyServer.toProxyAddress());
19567407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      }
1957e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
19587407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      @Override public void connectFailed(URI uri, SocketAddress address, IOException failure) {
19597407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        throw new AssertionError();
19607407d6984ce69693097befc9b72609a8156463bbNarayan Kamath      }
19617407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    });
196254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
19637407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    server2.enqueue(new MockResponse().setBody("This is the 2nd server!"));
19647407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
19657407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
19667407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        .addHeader("Location: " + server2.getUrl("/b").toString())
19677407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        .setBody("This page has moved!"));
19687407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
19697407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertContent("This is the 2nd server!", client.open(server.getUrl("/a")));
19707407d6984ce69693097befc9b72609a8156463bbNarayan Kamath
19717407d6984ce69693097befc9b72609a8156463bbNarayan Kamath    assertEquals(Arrays.asList(server.getUrl("/a").toURI(), server2.getUrl("/b").toURI()),
19727407d6984ce69693097befc9b72609a8156463bbNarayan Kamath        proxySelectionRequests);
1973e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
197454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
1975e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void redirectWithAuthentication() throws Exception {
1976e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server2.enqueue(new MockResponse().setBody("Page 2"));
1977e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1978e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setResponseCode(401));
1979e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setResponseCode(302)
1980e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Location: " + server2.getUrl("/b")));
1981e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1982e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setAuthenticator(
1983e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        new RecordingOkAuthenticator(Credentials.basic("jesse", "secret")));
1984e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("Page 2", client.open(server.getUrl("/a")));
1985e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
1986e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest redirectRequest = server2.takeRequest();
1987e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(redirectRequest.getHeader("Authorization"));
1988e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("/b", redirectRequest.getPath());
198954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
199054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
199154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void response300MultipleChoiceWithPost() throws Exception {
199254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Chrome doesn't follow the redirect, but Firefox and the RI both do
199378092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller    testResponseRedirectedWithPost(HttpURLConnection.HTTP_MULT_CHOICE, TransferKind.END_OF_STREAM);
199454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
199554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
199654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void response301MovedPermanentlyWithPost() throws Exception {
199778092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller    testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_PERM, TransferKind.END_OF_STREAM);
199854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
199954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
200054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void response302MovedTemporarilyWithPost() throws Exception {
200178092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller    testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_TEMP, TransferKind.END_OF_STREAM);
200254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
200354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
200454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void response303SeeOtherWithPost() throws Exception {
200578092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller    testResponseRedirectedWithPost(HttpURLConnection.HTTP_SEE_OTHER, TransferKind.END_OF_STREAM);
200654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
200754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
200878092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller  @Test public void postRedirectToGetWithChunkedRequest() throws Exception {
200978092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller    testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_TEMP, TransferKind.CHUNKED);
201078092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller  }
201178092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller
201278092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller  @Test public void postRedirectToGetWithStreamedRequest() throws Exception {
201378092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller    testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_TEMP, TransferKind.FIXED_LENGTH);
201478092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller  }
201578092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller
201678092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller  private void testResponseRedirectedWithPost(int redirectCode, TransferKind transferKind)
201778092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller      throws Exception {
201854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(redirectCode)
201954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: /page2")
202054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("This page has moved!"));
202154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("Page 2"));
202254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
20233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/page1"));
202454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
202578092f38ebd93018ead53a87b53118dc829cbb8aNeil Fuller    transferKind.setForRequest(connection, 4);
202654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    byte[] requestBody = { 'A', 'B', 'C', 'D' };
202754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    OutputStream outputStream = connection.getOutputStream();
202854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.write(requestBody);
202954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    outputStream.close();
203054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("Page 2", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
203154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertTrue(connection.getDoOutput());
203254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
203354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest page1 = server.takeRequest();
203454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("POST /page1 HTTP/1.1", page1.getRequestLine());
2035e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("ABCD", page1.getBody().readUtf8());
203654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
203754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest page2 = server.takeRequest();
203854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /page2 HTTP/1.1", page2.getRequestLine());
203954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
204054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2041166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath  @Test public void redirectedPostStripsRequestBodyHeaders() throws Exception {
2042e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
2043166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath        .addHeader("Location: /page2"));
2044166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    server.enqueue(new MockResponse().setBody("Page 2"));
2045166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath
20463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/page1"));
2047166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    connection.setDoOutput(true);
2048166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    connection.addRequestProperty("Content-Length", "4");
2049166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    connection.addRequestProperty("Content-Type", "text/plain; charset=utf-8");
2050166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    connection.addRequestProperty("Transfer-Encoding", "identity");
2051166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    OutputStream outputStream = connection.getOutputStream();
2052166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    outputStream.write("ABCD".getBytes("UTF-8"));
2053166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    outputStream.close();
2054166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    assertEquals("Page 2", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
2055166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath
2056166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    assertEquals("POST /page1 HTTP/1.1", server.takeRequest().getRequestLine());
2057166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath
2058166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    RecordedRequest page2 = server.takeRequest();
2059166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath    assertEquals("GET /page2 HTTP/1.1", page2.getRequestLine());
2060e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(page2.getHeader("Content-Length"));
2061e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(page2.getHeader("Content-Type"));
2062e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(page2.getHeader("Transfer-Encoding"));
2063166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath  }
2064166772be0e5cfdaea1a64b9f63e4c8dbfe48cba3Narayan Kamath
206554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void response305UseProxy() throws Exception {
206654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_USE_PROXY)
206754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: " + server.getUrl("/"))
206854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("This page has moved!"));
206954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("Proxy Response"));
207054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
20713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
207254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Fails on the RI, which gets "Proxy Response"
207354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("This page has moved!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
207454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
207554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest page1 = server.takeRequest();
207654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /foo HTTP/1.1", page1.getRequestLine());
207754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(1, server.getRequestCount());
207854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
207954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2080faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void response307WithGet() throws Exception {
2081e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(true, "GET");
2082faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2083faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2084faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void response307WithHead() throws Exception {
2085e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(true, "HEAD");
2086faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2087faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2088faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void response307WithOptions() throws Exception {
2089e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(true, "OPTIONS");
2090faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2091faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2092faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void response307WithPost() throws Exception {
2093e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(true, "POST");
2094e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2095e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2096e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void response308WithGet() throws Exception {
2097e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(false, "GET");
2098e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2099e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2100e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void response308WithHead() throws Exception {
2101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(false, "HEAD");
2102e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2103e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2104e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void response308WithOptions() throws Exception {
2105e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(false, "OPTIONS");
2106e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2107e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2108e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void response308WithPost() throws Exception {
2109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    testRedirect(false, "POST");
2110faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2111faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2112e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private void testRedirect(boolean temporary, String method) throws Exception {
2113faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    MockResponse response1 = new MockResponse()
2114e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setResponseCode(temporary ? HTTP_TEMP_REDIRECT : HTTP_PERM_REDIRECT)
2115faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath        .addHeader("Location: /page2");
2116faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    if (!method.equals("HEAD")) {
2117faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      response1.setBody("This page has moved!");
2118faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
2119faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(response1);
2120faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("Page 2"));
2121faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
21223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/page1"));
2123faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    connection.setRequestMethod(method);
2124faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    byte[] requestBody = { 'A', 'B', 'C', 'D' };
2125faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    if (method.equals("POST")) {
2126faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      connection.setDoOutput(true);
2127faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      OutputStream outputStream = connection.getOutputStream();
2128faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      outputStream.write(requestBody);
2129faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      outputStream.close();
2130faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
2131faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2132faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    String response = readAscii(connection.getInputStream(), Integer.MAX_VALUE);
2133faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2134faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    RecordedRequest page1 = server.takeRequest();
2135faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertEquals(method + " /page1 HTTP/1.1", page1.getRequestLine());
2136faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2137faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    if (method.equals("GET")) {
2138d7254e38efa2f20db6cac1a5cb5ac4548edc3d46Neil Fuller      assertEquals("Page 2", response);
2139e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    } else if (method.equals("HEAD"))  {
2140d7254e38efa2f20db6cac1a5cb5ac4548edc3d46Neil Fuller      assertEquals("", response);
2141faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    } else {
2142faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      // Methods other than GET/HEAD shouldn't follow the redirect
2143faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      if (method.equals("POST")) {
2144faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath        assertTrue(connection.getDoOutput());
2145e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        assertEquals("ABCD", page1.getBody().readUtf8());
2146faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      }
2147faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      assertEquals(1, server.getRequestCount());
2148faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      assertEquals("This page has moved!", response);
2149faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      return;
2150faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
2151faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2152faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    // GET/HEAD requests should have followed the redirect with the same method
2153faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertFalse(connection.getDoOutput());
2154faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertEquals(2, server.getRequestCount());
2155faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    RecordedRequest page2 = server.takeRequest();
2156faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertEquals(method + " /page2 HTTP/1.1", page2.getRequestLine());
2157faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2158faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
215954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void follow20Redirects() throws Exception {
216054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    for (int i = 0; i < 20; i++) {
216154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
216254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          .addHeader("Location: /" + (i + 1))
216354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          .setBody("Redirecting to /" + (i + 1)));
216454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
216554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("Success!"));
216654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
21673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/0"));
216854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("Success!", connection);
216954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(server.getUrl("/20"), connection.getURL());
217054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
217154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
217254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void doesNotFollow21Redirects() throws Exception {
217354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    for (int i = 0; i < 21; i++) {
217454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
217554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          .addHeader("Location: /" + (i + 1))
217654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          .setBody("Redirecting to /" + (i + 1)));
217754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
217854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
21793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/0"));
218054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
218154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getInputStream();
218254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
218354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (ProtocolException expected) {
218454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals(HttpURLConnection.HTTP_MOVED_TEMP, connection.getResponseCode());
2185e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      assertEquals("Too many follow-up requests: 21", expected.getMessage());
218654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertContent("Redirecting to /21", connection);
218754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals(server.getUrl("/20"), connection.getURL());
218854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
218954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
219054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
219154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void httpsWithCustomTrustManager() throws Exception {
219254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
219354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordingTrustManager trustManager = new RecordingTrustManager();
219454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    SSLContext sc = SSLContext.getInstance("TLS");
219554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    sc.init(null, new TrustManager[] { trustManager }, new java.security.SecureRandom());
219654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2197e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(hostnameVerifier);
2198e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sc.getSocketFactory());
219971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
220054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("ABC"));
220154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("DEF"));
220254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("GHI"));
220354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
220454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URL url = server.getUrl("/");
220554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("ABC", client.open(url));
220654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("DEF", client.open(url));
220754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("GHI", client.open(url));
220854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
220971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(Arrays.asList("verify " + server.getHostName()),
2210e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        hostnameVerifier.calls);
221171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(Arrays.asList("checkServerTrusted [CN=" + server.getHostName() + " 1]"),
2212e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        trustManager.calls);
221354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
221454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
221554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void readTimeouts() throws IOException {
221654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // This relies on the fact that MockWebServer doesn't close the
221754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // connection after a response has been sent. This causes the client to
221854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // try to read more bytes than are sent, which results in a timeout.
221954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse timeout =
222054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        new MockResponse().setBody("ABC").clearHeaders().addHeader("Content-Length: 4");
222154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(timeout);
222254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("unused")); // to keep the server alive
222354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
22243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    URLConnection connection = client.open(server.getUrl("/"));
22253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setReadTimeout(1000);
22263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    InputStream in = connection.getInputStream();
222754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals('A', in.read());
222854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals('B', in.read());
222954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals('C', in.read());
223054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
223154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      in.read(); // if Content-Length was accurate, this would return -1 immediately
223254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
2233b5f9076b16fcc41c3dad31aecfdcfd962a7a1f75Neil Fuller    } catch (SocketTimeoutException expected) {
2234e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    }
2235e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2236e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  /** Confirm that an unacknowledged write times out. */
2238e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void writeTimeouts() throws IOException {
2239d22dae2ff3c14d458829d7082651f3e6baa9b65dNeil Fuller    MockWebServer server = new MockWebServer();
2240e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    // Sockets on some platforms can have large buffers that mean writes do not block when
2241e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    // required. These socket factories explicitly set the buffer sizes on sockets created.
2242e0d02d710cd1bbcc1a9065ede7f6801f72abe5b7Neil Fuller    final int SOCKET_BUFFER_SIZE = 4 * 1024;
224371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.setServerSocketFactory(
2244e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        new DelegatingServerSocketFactory(ServerSocketFactory.getDefault()) {
2245e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          @Override
224671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller          protected ServerSocket configureServerSocket(ServerSocket serverSocket)
224771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller              throws IOException {
2248e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller            serverSocket.setReceiveBufferSize(SOCKET_BUFFER_SIZE);
224971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller            return serverSocket;
2250e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          }
2251e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        });
2252e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSocketFactory(new DelegatingSocketFactory(SocketFactory.getDefault()) {
2253e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override
225471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      protected Socket configureSocket(Socket socket) throws IOException {
2255e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        socket.setReceiveBufferSize(SOCKET_BUFFER_SIZE);
2256e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        socket.setSendBufferSize(SOCKET_BUFFER_SIZE);
225771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        return socket;
2258e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      }
2259e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    });
2260e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2261d22dae2ff3c14d458829d7082651f3e6baa9b65dNeil Fuller    server.start();
2262e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
2263e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .throttleBody(1, 1, TimeUnit.SECONDS)); // Prevent the server from reading!
2264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setWriteTimeout(500, TimeUnit.MILLISECONDS);
2266e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/"));
2267e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.setDoOutput(true);
2268e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.setChunkedStreamingMode(0);
2269e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    OutputStream out = connection.getOutputStream();
2270e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    try {
2271e0d02d710cd1bbcc1a9065ede7f6801f72abe5b7Neil Fuller      byte[] data = new byte[2 * 1024 * 1024]; // 2 MiB.
2272e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      out.write(data);
2273e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      fail();
2274b5f9076b16fcc41c3dad31aecfdcfd962a7a1f75Neil Fuller    } catch (SocketTimeoutException expected) {
227554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
227654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
227754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
227854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void setChunkedEncodingAsRequestProperty() throws IOException, InterruptedException {
227954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
228054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
22813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
22823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setRequestProperty("Transfer-encoding", "chunked");
22833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
22843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().write("ABC".getBytes("UTF-8"));
22853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(200, connection.getResponseCode());
228654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
228754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
2288e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("ABC", request.getBody().readUtf8());
228954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
229054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
229154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectionCloseInRequest() throws IOException, InterruptedException {
229254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse()); // server doesn't honor the connection: close header!
229354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
229454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
229554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection a = client.open(server.getUrl("/"));
229654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    a.setRequestProperty("Connection", "close");
229754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(200, a.getResponseCode());
229854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
229954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection b = client.open(server.getUrl("/"));
230054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(200, b.getResponseCode());
230154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
230254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
230354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("When connection: close is used, each request should get its own connection", 0,
230454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        server.takeRequest().getSequenceNumber());
230554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
230654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
230754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectionCloseInResponse() throws IOException, InterruptedException {
230854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().addHeader("Connection: close"));
230954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
231054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
231154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection a = client.open(server.getUrl("/"));
231254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(200, a.getResponseCode());
231354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
231454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HttpURLConnection b = client.open(server.getUrl("/"));
231554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(200, b.getResponseCode());
231654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
231754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
231854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("When connection: close is used, each request should get its own connection", 0,
231954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        server.takeRequest().getSequenceNumber());
232054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
232154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
232254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void connectionCloseWithRedirect() throws IOException, InterruptedException {
232354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
232454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: /foo")
232554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Connection: close");
232654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
232754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("This is the new location!"));
232854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
232954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
233054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("This is the new location!",
233154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        readAscii(connection.getInputStream(), Integer.MAX_VALUE));
233254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
233354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
233454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("When connection: close is used, each request should get its own connection", 0,
233554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        server.takeRequest().getSequenceNumber());
233654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
233754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
233854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
233954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Retry redirects if the socket is closed.
234054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * https://code.google.com/p/android/issues/detail?id=41576
234154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
234254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void sameConnectionRedirectAndReuse() throws Exception {
234354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
234454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setSocketPolicy(SHUTDOWN_INPUT_AT_END)
234554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Location: /foo"));
234654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("This is the new page!"));
234754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
234854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent("This is the new page!", client.open(server.getUrl("/")));
234954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
235054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
235154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, server.takeRequest().getSequenceNumber());
235254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
235354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
235454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void responseCodeDisagreesWithHeaders() throws IOException, InterruptedException {
235554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)
235654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setBody("This body is not allowed!"));
235754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
235854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    URLConnection connection = client.open(server.getUrl("/"));
235954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("This body is not allowed!",
236054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        readAscii(connection.getInputStream(), Integer.MAX_VALUE));
236154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
236254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
236354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void singleByteReadIsSigned() throws IOException {
2364e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody(new Buffer().writeByte(-2).writeByte(-1)));
236554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
23663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
236754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in = connection.getInputStream();
236854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(254, in.read());
236954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(255, in.read());
237054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(-1, in.read());
237154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
237254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
237354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void flushAfterStreamTransmittedWithChunkedEncoding() throws IOException {
237454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testFlushAfterStreamTransmitted(TransferKind.CHUNKED);
237554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
237654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
237754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void flushAfterStreamTransmittedWithFixedLength() throws IOException {
237854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testFlushAfterStreamTransmitted(TransferKind.FIXED_LENGTH);
237954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
238054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
238154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void flushAfterStreamTransmittedWithNoLengthHeaders() throws IOException {
238254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testFlushAfterStreamTransmitted(TransferKind.END_OF_STREAM);
238354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
238454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
238554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
238654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * We explicitly permit apps to close the upload stream even after it has
238754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * been transmitted.  We also permit flush so that buffered streams can
238854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * do a no-op flush when they are closed. http://b/3038470
238954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
239054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testFlushAfterStreamTransmitted(TransferKind transferKind) throws IOException {
239154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("abc"));
239254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
23933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
239454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
239554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    byte[] upload = "def".getBytes("UTF-8");
239654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
239754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    if (transferKind == TransferKind.CHUNKED) {
239854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setChunkedStreamingMode(0);
239954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } else if (transferKind == TransferKind.FIXED_LENGTH) {
240054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setFixedLengthStreamingMode(upload.length);
240154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
240254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
240354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    OutputStream out = connection.getOutputStream();
240454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    out.write(upload);
240554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("abc", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
240654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
24073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    out.flush(); // Dubious but permitted.
240854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
240954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      out.write("ghi".getBytes("UTF-8"));
241054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
241154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
241254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
241354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
241454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
241554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getHeadersThrows() throws IOException {
2416e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setSocketPolicy(DISCONNECT_AT_START));
241754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
24183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
241954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
242054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getInputStream();
242154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
242254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
242354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
242454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
242554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
242654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getInputStream();
242754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
242854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
242954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
243054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
243154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
243254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void dnsFailureThrowsIOException() throws IOException {
24333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(new URL("http://host.unlikelytld"));
243454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
243554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.connect();
243654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
243754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IOException expected) {
243854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
243954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
244054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
244154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void malformedUrlThrowsUnknownHostException() throws IOException {
24426dde4fd274c15786415a313faf5b4506e3d712e4jwilson    connection = client.open(new URL("http://./foo.html"));
244354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
244454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.connect();
244554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
244654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (UnknownHostException expected) {
244754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
244854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
244954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
245054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getKeepAlive() throws Exception {
245154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("ABC"));
245254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
245354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // The request should work once and then fail
245471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    HttpURLConnection connection1 = client.open(server.getUrl("/"));
245554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection1.setReadTimeout(100);
245654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream input = connection1.getInputStream();
245754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("ABC", readAscii(input, Integer.MAX_VALUE));
245871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.shutdown();
245954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
246054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      HttpURLConnection connection2 = client.open(server.getUrl(""));
246154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection2.setReadTimeout(100);
246254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection2.getInputStream();
246354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
246454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (ConnectException expected) {
246554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
246654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
246754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
246854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** http://code.google.com/p/android/issues/detail?id=14562 */
246954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void readAfterLastByte() throws Exception {
247054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("ABC")
247154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .clearHeaders()
247254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .addHeader("Connection: close")
247354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END));
247454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
24753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
247654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in = connection.getInputStream();
247754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("ABC", readAscii(in, 3));
247854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(-1, in.read());
247954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(-1, in.read()); // throws IOException in Gingerbread
248054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
248154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
248254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getContent() throws Exception {
248354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().addHeader("Content-Type: text/plain").setBody("A"));
24843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
248554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in = (InputStream) connection.getContent();
248654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("A", readAscii(in, Integer.MAX_VALUE));
248754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
248854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
248954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getContentOfType() throws Exception {
249054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().addHeader("Content-Type: text/plain").setBody("A"));
24913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
249254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
249354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getContent(null);
249454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
249554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (NullPointerException expected) {
249654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
249754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
249854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getContent(new Class[] { null });
249954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
250054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (NullPointerException expected) {
250154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
250271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertNull(connection.getContent(new Class[] { getClass() }));
250354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
250454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
250554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getOutputStreamOnGetFails() throws Exception {
250654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
25073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
250854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
250954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getOutputStream();
251054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
251154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (ProtocolException expected) {
251254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
251354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
251454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
251554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getOutputAfterGetInputStreamFails() throws Exception {
251654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
25173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
251854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
251954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
252054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getInputStream();
252154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.getOutputStream();
252254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
252354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (ProtocolException expected) {
252454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
252554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
252654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
252754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void setDoOutputOrDoInputAfterConnectFails() throws Exception {
252854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse());
25293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
253054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.connect();
253154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
253254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setDoOutput(true);
253354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
253454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
253554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
253654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    try {
253754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      connection.setDoInput(true);
253854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      fail();
253954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    } catch (IllegalStateException expected) {
254054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
254154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
254254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
254354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void clientSendsContentLength() throws Exception {
254454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("A"));
25453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
254654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.setDoOutput(true);
254754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    OutputStream out = connection.getOutputStream();
254854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    out.write(new byte[] { 'A', 'B', 'C' });
254954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    out.close();
255054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
255154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
2552e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("3", request.getHeader("Content-Length"));
255354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
255454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
255554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getContentLengthConnects() throws Exception {
255654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("ABC"));
25573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
255854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(3, connection.getContentLength());
255954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
256054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
256154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getContentTypeConnects() throws Exception {
256254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().addHeader("Content-Type: text/plain").setBody("ABC"));
25633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
256454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("text/plain", connection.getContentType());
256554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
256654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
256754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void getContentEncodingConnects() throws Exception {
256854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().addHeader("Content-Encoding: identity").setBody("ABC"));
25693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
257054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("identity", connection.getContentEncoding());
257154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
257254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
257354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // http://b/4361656
257454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void urlContainsQueryButNoPath() throws Exception {
257554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(new MockResponse().setBody("A"));
2576e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
257771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    URL url = new URL("http", server.getHostName(), server.getPort(), "?query");
257854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("A", readAscii(client.open(url).getInputStream(), Integer.MAX_VALUE));
257954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    RecordedRequest request = server.takeRequest();
258054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals("GET /?query HTTP/1.1", request.getRequestLine());
258154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
258254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2583e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void doOutputForMethodThatDoesntSupportOutput() throws Exception {
2584e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/"));
2585e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.setRequestMethod("HEAD");
2586e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.setDoOutput(true);
2587e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    try {
2588e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      connection.connect();
2589e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      fail();
2590e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    } catch (IOException expected) {
2591e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    }
2592e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2593e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
259454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  // http://code.google.com/p/android/issues/detail?id=20442
259554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void inputStreamAvailableWithChunkedEncoding() throws Exception {
259654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testInputStreamAvailable(TransferKind.CHUNKED);
259754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
259854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
259954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void inputStreamAvailableWithContentLengthHeader() throws Exception {
260054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testInputStreamAvailable(TransferKind.FIXED_LENGTH);
260154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
260254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
260354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test public void inputStreamAvailableWithNoLengthHeaders() throws Exception {
260454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    testInputStreamAvailable(TransferKind.END_OF_STREAM);
260554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
260654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
260754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private void testInputStreamAvailable(TransferKind transferKind) throws IOException {
260854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    String body = "ABCDEFGH";
260954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    MockResponse response = new MockResponse();
261054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    transferKind.setBody(response, body, 4);
261154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    server.enqueue(response);
26123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
261354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    InputStream in = connection.getInputStream();
261454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    for (int i = 0; i < body.length(); i++) {
261554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertTrue(in.available() >= 0);
261654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      assertEquals(body.charAt(i), in.read());
261754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
261854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(0, in.available());
261954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(-1, in.read());
262054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
262154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2622faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void postFailsWithBufferedRequestForSmallRequest() throws Exception {
2623faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    reusedConnectionFailsWithPost(TransferKind.END_OF_STREAM, 1024);
2624faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2625faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2626fb0eb65be9f50e75fa37c250e97914252c587cafjwilson  @Test public void postFailsWithBufferedRequestForLargeRequest() throws Exception {
2627faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    reusedConnectionFailsWithPost(TransferKind.END_OF_STREAM, 16384);
2628faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2629faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2630faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void postFailsWithChunkedRequestForSmallRequest() throws Exception {
2631faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    reusedConnectionFailsWithPost(TransferKind.CHUNKED, 1024);
2632faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2633faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2634fb0eb65be9f50e75fa37c250e97914252c587cafjwilson  @Test public void postFailsWithChunkedRequestForLargeRequest() throws Exception {
2635faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    reusedConnectionFailsWithPost(TransferKind.CHUNKED, 16384);
2636faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2637faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2638faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void postFailsWithFixedLengthRequestForSmallRequest() throws Exception {
2639faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    reusedConnectionFailsWithPost(TransferKind.FIXED_LENGTH, 1024);
2640faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2641faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2642fb0eb65be9f50e75fa37c250e97914252c587cafjwilson  @Test public void postFailsWithFixedLengthRequestForLargeRequest() throws Exception {
2643faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    reusedConnectionFailsWithPost(TransferKind.FIXED_LENGTH, 16384);
2644faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2645faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2646faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  private void reusedConnectionFailsWithPost(TransferKind transferKind, int requestSize)
2647faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      throws Exception {
2648e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("A").setSocketPolicy(DISCONNECT_AT_END));
2649faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("B"));
26503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("C"));
2651faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2652faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertContent("A", client.open(server.getUrl("/a")));
2653faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2654faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    // If the request body is larger than OkHttp's replay buffer, the failure may still occur.
2655faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    byte[] requestBody = new byte[requestSize];
2656faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    new Random(0).nextBytes(requestBody);
2657faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2658a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller    for (int j = 0; j < 2; j++) {
2659a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller      try {
2660a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        connection = client.open(server.getUrl("/b"));
2661a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        connection.setRequestMethod("POST");
2662a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        transferKind.setForRequest(connection, requestBody.length);
2663a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        for (int i = 0; i < requestBody.length; i += 1024) {
2664a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller          connection.getOutputStream().write(requestBody, i, 1024);
2665a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        }
2666a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        connection.getOutputStream().close();
2667a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        assertContent("B", connection);
2668a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        break;
2669a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller      } catch (IOException socketException) {
2670a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        // If there's a socket exception, this must have a streamed request body.
2671a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        assertEquals(0, j);
2672a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller        assertTrue(transferKind == TransferKind.CHUNKED
2673a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller            || transferKind == TransferKind.FIXED_LENGTH);
2674a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller      }
2675faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
2676faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2677faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    RecordedRequest requestA = server.takeRequest();
2678faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertEquals("/a", requestA.getPath());
2679faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    RecordedRequest requestB = server.takeRequest();
2680faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertEquals("/b", requestB.getPath());
2681e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(Arrays.toString(requestBody), Arrays.toString(requestB.getBody().readByteArray()));
2682e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2683e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2684e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void postBodyRetransmittedOnFailureRecovery() throws Exception {
2685e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("abc"));
2686e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST));
2687e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("def"));
2688e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2689e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    // Seed the connection pool so we have something that can fail.
2690e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("abc", client.open(server.getUrl("/")));
2691e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2692e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection post = client.open(server.getUrl("/"));
2693e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    post.setDoOutput(true);
2694e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    post.getOutputStream().write("body!".getBytes(Util.UTF_8));
2695e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("def", post);
2696e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2697e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest get = server.takeRequest();
2698e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(0, get.getSequenceNumber());
2699e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2700e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest post1 = server.takeRequest();
2701e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("body!", post1.getBody().readUtf8());
2702e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(1, post1.getSequenceNumber());
2703e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2704e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest post2 = server.takeRequest();
2705e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("body!", post2.getBody().readUtf8());
2706e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(0, post2.getSequenceNumber());
2707faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2708faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2709faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void fullyBufferedPostIsTooShort() throws Exception {
2710faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("A"));
2711faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
27123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/b"));
2713faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    connection.setRequestProperty("Content-Length", "4");
2714faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    connection.setRequestMethod("POST");
2715faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    OutputStream out = connection.getOutputStream();
2716faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    out.write('a');
2717faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    out.write('b');
2718faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    out.write('c');
2719faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    try {
2720faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      out.close();
2721faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      fail();
2722faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    } catch (IOException expected) {
2723faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
2724faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2725faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2726faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void fullyBufferedPostIsTooLong() throws Exception {
2727faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("A"));
2728faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
27293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/b"));
2730faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    connection.setRequestProperty("Content-Length", "3");
2731faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    connection.setRequestMethod("POST");
2732faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    OutputStream out = connection.getOutputStream();
2733faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    out.write('a');
2734faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    out.write('b');
2735faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    out.write('c');
2736faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    try {
2737faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      out.write('d');
27383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      out.flush();
2739faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      fail();
2740faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    } catch (IOException expected) {
2741faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
2742faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2743faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
274454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void testPooledConnectionsDetectHttp10() {
274554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // TODO: write a test that shows pooled connections detect HTTP/1.0 (vs. HTTP/1.1)
274654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
274754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
274854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
274954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void postBodiesRetransmittedOnAuthProblems() {
275054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
275154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
275254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
275354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void cookiesAndTrailers() {
275454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // Do cookie headers get processed too many times?
275554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
275654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
275754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
275854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void headerNamesContainingNullCharacter() {
275954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // This is relevant for SPDY
276054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
276154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
276254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
276354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void headerValuesContainingNullCharacter() {
276454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    // This is relevant for SPDY
276554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
276654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
276754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2768faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void emptyRequestHeaderValueIsAllowed() throws Exception {
2769faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("body"));
27703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
27713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.addRequestProperty("B", "");
27723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("body", connection);
27733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("", connection.getRequestProperty("B"));
277454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
277554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2776faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void emptyResponseHeaderValueIsAllowed() throws Exception {
2777faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().addHeader("A:").setBody("body"));
27783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
27793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("body", connection);
27803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("", connection.getHeaderField("A"));
2781faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2782faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2783faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void emptyRequestHeaderNameIsStrict() throws Exception {
2784faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("body"));
27853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
2786faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    try {
27873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      connection.setRequestProperty("", "A");
2788faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      fail();
2789faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    } catch (IllegalArgumentException expected) {
2790faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
2791faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2792faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2793faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  @Test public void emptyResponseHeaderNameIsLenient() throws Exception {
2794e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Headers.Builder headers = new Headers.Builder();
2795e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Internal.instance.addLenient(headers, ":A");
2796e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setHeaders(headers.build()).setBody("body"));
27973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
27983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getResponseCode();
27993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("A", connection.getHeaderField(""));
280054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
280154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
280271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void requestHeaderValidationIsStrict() throws Exception {
280371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    connection = client.open(server.getUrl("/"));
280471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
280571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      connection.addRequestProperty("a\tb", "Value");
280671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
280771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (IllegalArgumentException expected) {
280871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
280971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
281071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      connection.addRequestProperty("Name", "c\u007fd");
281171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
281271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (IllegalArgumentException expected) {
281371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
281471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
281571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      connection.addRequestProperty("", "Value");
281671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
281771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (IllegalArgumentException expected) {
281871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
281971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
282071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      connection.addRequestProperty("\ud83c\udf69", "Value");
282171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
282271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (IllegalArgumentException expected) {
282371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
282475687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller
282575687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller    // ANDROID-BEGIN Disabled for http://b/28867041
282675687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller    // try {
282775687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller    //   connection.addRequestProperty("Name", "\u2615\ufe0f");
282875687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller    //   fail();
282975687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller    // } catch (IllegalArgumentException expected) {
283075687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller    // }
283175687ca5ae54f417afb4c02ba04767da6786d829Neil Fuller    // ANDROID-END
283271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
283371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
283471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void responseHeaderParsingIsLenient() throws Exception {
283571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    Headers headers = new Headers.Builder()
283671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .add("Content-Length", "0")
283771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .addLenient("a\tb: c\u007fd")
283871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .addLenient(": ef")
283971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .addLenient("\ud83c\udf69: \u2615\ufe0f")
284071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .build();
284171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.enqueue(new MockResponse().setHeaders(headers));
284271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
284371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    connection = client.open(server.getUrl("/"));
284471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    connection.getResponseCode();
284571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals("c\u007fd", connection.getHeaderField("a\tb"));
284671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals("\u2615\ufe0f", connection.getHeaderField("\ud83c\udf69"));
284771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals("ef", connection.getHeaderField(""));
284871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
284971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
285054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void deflateCompression() {
285154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
285254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
285354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
285454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void postBodiesRetransmittedOnIpAddressProblems() {
285554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
285654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
285754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
285854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  @Test @Ignore public void pooledConnectionProblemsNotReportedToProxySelector() {
285954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    fail("TODO");
286054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
286154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
2862e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void customBasicAuthenticator() throws Exception {
2863faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(401)
2864faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath        .addHeader("WWW-Authenticate: Basic realm=\"protected area\"")
2865faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath        .setBody("Please authenticate.");
2866faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(pleaseAuthenticate);
2867faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("A"));
2868faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2869e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    String credential = Credentials.basic("jesse", "peanutbutter");
2870faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator(credential);
2871e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setAuthenticator(authenticator);
2872faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertContent("A", client.open(server.getUrl("/private")));
2873faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2874e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(server.takeRequest().getHeader("Authorization"));
2875e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(credential, server.takeRequest().getHeader("Authorization"));
2876faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2877f6af62d5c9bb5e15649a80ebae973463e8e2dc46Neil Fuller    assertEquals(Proxy.NO_PROXY, authenticator.onlyProxy());
2878e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Response response = authenticator.onlyResponse();
2879e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("/private", response.request().url().getPath());
2880e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(Arrays.asList(new Challenge("Basic", "protected area")), response.challenges());
2881faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
2882faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
2883e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void customTokenAuthenticator() throws Exception {
2884e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    MockResponse pleaseAuthenticate = new MockResponse().setResponseCode(401)
2885e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller            .addHeader("WWW-Authenticate: Bearer realm=\"oauthed\"")
2886e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller            .setBody("Please authenticate.");
2887e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(pleaseAuthenticate);
2888e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("A"));
2889e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2890e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator("oauthed abc123");
2891e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setAuthenticator(authenticator);
2892e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("A", client.open(server.getUrl("/private")));
2893e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2894e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertNull(server.takeRequest().getHeader("Authorization"));
2895e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("oauthed abc123", server.takeRequest().getHeader("Authorization"));
2896e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2897e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Response response = authenticator.onlyResponse();
2898e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("/private", response.request().url().getPath());
2899e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(Arrays.asList(new Challenge("Bearer", "oauthed")), response.challenges());
29003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
29013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2902e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void authenticateCallsTrackedAsRedirects() throws Exception {
2903e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
2904e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setResponseCode(302)
2905e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Location: /b"));
2906e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
2907e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setResponseCode(401)
2908e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("WWW-Authenticate: Basic realm=\"protected area\""));
2909e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("c"));
2910e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2911e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordingOkAuthenticator authenticator = new RecordingOkAuthenticator(
2912e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        Credentials.basic("jesse", "peanutbutter"));
2913e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setAuthenticator(authenticator);
2914e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("c", client.open(server.getUrl("/a")));
2915e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2916e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Response challengeResponse = authenticator.responses.get(0);
2917e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("/b", challengeResponse.request().url().getPath());
2918e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2919e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Response redirectedBy = challengeResponse.priorResponse();
2920e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("/a", redirectedBy.request().url().getPath());
2921e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2922e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2923e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void attemptAuthorization20Times() throws Exception {
2924e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    for (int i = 0; i < 20; i++) {
2925e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      server.enqueue(new MockResponse().setResponseCode(401));
2926e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    }
2927e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("Success!"));
2928e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2929e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    String credential = Credentials.basic("jesse", "peanutbutter");
2930e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setAuthenticator(new RecordingOkAuthenticator(credential));
2931e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2932e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/0"));
2933e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("Success!", connection);
29343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
29353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2936e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void doesNotAttemptAuthorization21Times() throws Exception {
2937e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    for (int i = 0; i < 21; i++) {
2938e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      server.enqueue(new MockResponse().setResponseCode(401));
2939e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    }
2940e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2941e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    String credential = Credentials.basic("jesse", "peanutbutter");
2942e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setAuthenticator(new RecordingOkAuthenticator(credential));
2943e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2944e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/"));
2945e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    try {
2946e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      connection.getInputStream();
2947e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      fail();
2948e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    } catch (ProtocolException expected) {
2949e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      assertEquals(401, connection.getResponseCode());
2950e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      assertEquals("Too many follow-up requests: 21", expected.getMessage());
2951e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    }
2952e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2953e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2954e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void setsNegotiatedProtocolHeader_SPDY_3() throws Exception {
2955e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    setsNegotiatedProtocolHeader(Protocol.SPDY_3);
2956e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2957e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2958e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void setsNegotiatedProtocolHeader_HTTP_2() throws Exception {
2959e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    setsNegotiatedProtocolHeader(Protocol.HTTP_2);
2960e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2961e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2962e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private void setsNegotiatedProtocolHeader(Protocol protocol) throws IOException {
2963e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(protocol);
2964faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    server.enqueue(new MockResponse().setBody("A"));
2965e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setProtocols(Arrays.asList(protocol, Protocol.HTTP_1_1));
29663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
29673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    List<String> protocolValues = connection.getHeaderFields().get(SELECTED_PROTOCOL);
2968e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(Arrays.asList(protocol.toString()), protocolValues);
29693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", connection);
29703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
29713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2972e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void http10SelectedProtocol() throws Exception {
2973e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setStatus("HTTP/1.0 200 OK"));
2974e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/"));
2975e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    List<String> protocolValues = connection.getHeaderFields().get(SELECTED_PROTOCOL);
2976e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(Arrays.asList("http/1.0"), protocolValues);
2977e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2978e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
2979e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void http11SelectedProtocol() throws Exception {
2980e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setStatus("HTTP/1.1 200 OK"));
2981e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/"));
2982e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    List<String> protocolValues = connection.getHeaderFields().get(SELECTED_PROTOCOL);
2983e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(Arrays.asList("http/1.1"), protocolValues);
2984e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
2985e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
29863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /** For example, empty Protobuf RPC messages end up as a zero-length POST. */
29873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void zeroLengthPost() throws IOException, InterruptedException {
29883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    zeroLengthPayload("POST");
29893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
29903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
29913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void zeroLengthPost_SPDY_3() throws Exception {
2992e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.SPDY_3);
29933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    zeroLengthPost();
29943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
29953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
29963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void zeroLengthPost_HTTP_2() throws Exception {
2997e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.HTTP_2);
29983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    zeroLengthPost();
29993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
30003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
30013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /** For example, creating an Amazon S3 bucket ends up as a zero-length POST. */
30023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void zeroLengthPut() throws IOException, InterruptedException {
30033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    zeroLengthPayload("PUT");
30043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
30053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
30063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void zeroLengthPut_SPDY_3() throws Exception {
3007e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.SPDY_3);
30083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    zeroLengthPut();
30093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
30103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
30113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void zeroLengthPut_HTTP_2() throws Exception {
3012e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    enableProtocol(Protocol.HTTP_2);
30133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    zeroLengthPut();
30143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
30153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
30163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private void zeroLengthPayload(String method)
30173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      throws IOException, InterruptedException {
30183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse());
30193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
30203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setRequestProperty("Content-Length", "0");
30213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setRequestMethod(method);
30223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setFixedLengthStreamingMode(0);
30233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
30243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("", connection);
30253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest zeroLengthPayload = server.takeRequest();
30263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(method, zeroLengthPayload.getMethod());
30273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("0", zeroLengthPayload.getHeader("content-length"));
30283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0L, zeroLengthPayload.getBodySize());
30293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
30303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3031e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void unspecifiedRequestBodyContentTypeGetsDefault() throws Exception {
3032e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse());
3033e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3034e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection = client.open(server.getUrl("/"));
3035e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.setDoOutput(true);
3036e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.getOutputStream().write("abc".getBytes(UTF_8));
3037e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(200, connection.getResponseCode());
3038e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3039e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest request = server.takeRequest();
3040e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type"));
3041e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("3", request.getHeader("Content-Length"));
3042e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("abc", request.getBody().readUtf8());
3043e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
3044e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
30453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void setProtocols() throws Exception {
30463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("A"));
3047e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setProtocols(Arrays.asList(Protocol.HTTP_1_1));
3048faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    assertContent("A", client.open(server.getUrl("/")));
3049faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
3050faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
30513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void setProtocolsWithoutHttp11() throws Exception {
3052faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    try {
3053e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setProtocols(Arrays.asList(Protocol.SPDY_3));
3054faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      fail();
3055faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    } catch (IllegalArgumentException expected) {
3056faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
3057faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
3058faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
30593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void setProtocolsWithNull() throws Exception {
3060faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    try {
3061e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      client.client().setProtocols(Arrays.asList(Protocol.HTTP_1_1, null));
3062faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath      fail();
3063faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    } catch (IllegalArgumentException expected) {
3064faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath    }
3065faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath  }
3066faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath
3067a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath  @Test public void veryLargeFixedLengthRequest() throws Exception {
306871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.setBodyLimit(0);
3069a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    server.enqueue(new MockResponse());
3070a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath
30713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
3072a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    connection.setDoOutput(true);
3073a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    long contentLength = Integer.MAX_VALUE + 1L;
3074a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    connection.setFixedLengthStreamingMode(contentLength);
3075a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    OutputStream out = connection.getOutputStream();
3076a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    byte[] buffer = new byte[1024 * 1024];
3077a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    for (long bytesWritten = 0; bytesWritten < contentLength; ) {
3078a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath      int byteCount = (int) Math.min(buffer.length, contentLength - bytesWritten);
3079a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath      out.write(buffer, 0, byteCount);
3080a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath      bytesWritten += byteCount;
3081a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    }
3082a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    assertContent("", connection);
3083a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath
3084a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    RecordedRequest request = server.takeRequest();
3085a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath    assertEquals(Long.toString(contentLength), request.getHeader("Content-Length"));
3086a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath  }
3087a82f42bbeedd0b07f3892f3b0efaa8122dc8f264Narayan Kamath
30883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
30893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * We had a bug where we attempted to gunzip responses that didn't have a
30903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * body. This only came up with 304s since that response code can include
30913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * headers (like "Content-Encoding") without any content to go along with it.
30923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * https://github.com/square/okhttp/issues/358
30933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
30943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void noTransparentGzipFor304NotModified() throws Exception {
30953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse()
30963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .clearHeaders()
30973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)
30983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Content-Encoding: gzip"));
30993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("b"));
31003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection1 = client.open(server.getUrl("/"));
31023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(HttpURLConnection.HTTP_NOT_MODIFIED, connection1.getResponseCode());
31033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("", connection1);
31043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection2 = client.open(server.getUrl("/"));
31063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(HttpURLConnection.HTTP_OK, connection2.getResponseCode());
31073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("b", connection2);
31083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest requestA = server.takeRequest();
31103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, requestA.getSequenceNumber());
31113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest requestB = server.takeRequest();
31133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, requestB.getSequenceNumber());
31143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
31153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
31173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * We had a bug where we weren't closing Gzip streams on redirects.
31183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * https://github.com/square/okhttp/issues/441
31193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
31203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void gzipWithRedirectAndConnectionReuse() throws Exception {
31213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse()
31223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
31233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Location: /foo")
31243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Content-Encoding: gzip")
3125e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody(gzip("Moved! Moved! Moved!")));
31263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("This is the new page!"));
31273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection = client.open(server.getUrl("/"));
31293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("This is the new page!", connection);
31303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest requestA = server.takeRequest();
31323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, requestA.getSequenceNumber());
31333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest requestB = server.takeRequest();
31353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, requestB.getSequenceNumber());
31363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
31373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
31393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * The RFC is unclear in this regard as it only specifies that this should
31403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * invalidate the cache entry (if any).
31413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
31423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void bodyPermittedOnDelete() throws Exception {
31433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse());
31443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection = client.open(server.getUrl("/"));
31463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setRequestMethod("DELETE");
31473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
31483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().write("BODY".getBytes(UTF_8));
31493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(200, connection.getResponseCode());
31503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
31513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request = server.takeRequest();
31523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("DELETE", request.getMethod());
3153e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("BODY", request.getBody().readUtf8());
3154e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
3155e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3156e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void userAgentPicksUpHttpAgentSystemProperty() throws Exception {
3157e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("abc"));
3158e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3159e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    System.setProperty("http.agent", "foo");
3160e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("abc", client.open(server.getUrl("/")));
3161e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3162e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest request = server.takeRequest();
3163e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals("foo", request.getHeader("User-Agent"));
3164e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
3165e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
316671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  /** https://github.com/square/okhttp/issues/891 */
316771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void userAgentSystemPropertyIsNotAscii() throws Exception {
3168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("abc"));
3169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
317071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    System.setProperty("http.agent", "a\nb\ud83c\udf69c\ud83c\udf68d\u007fe");
3171e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("abc", client.open(server.getUrl("/")));
3172e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3173e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    RecordedRequest request = server.takeRequest();
317471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals("a?b?c?d?e", request.getHeader("User-Agent"));
317571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
317671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
317771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void userAgentDefaultsToOkHttpVersion() throws Exception {
317871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.enqueue(new MockResponse().setBody("abc"));
317971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
318071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertContent("abc", client.open(server.getUrl("/")));
318171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
318271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    RecordedRequest request = server.takeRequest();
318371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(Version.userAgent(), request.getHeader("User-Agent"));
3184e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
3185e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3186e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void interceptorsNotInvoked() throws Exception {
3187e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Interceptor interceptor = new Interceptor() {
3188e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override public Response intercept(Chain chain) throws IOException {
3189e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        throw new AssertionError();
3190e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      }
3191e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    };
3192e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().interceptors().add(interceptor);
3193e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().networkInterceptors().add(interceptor);
3194e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3195e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("abc"));
3196e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertContent("abc", client.open(server.getUrl("/")));
31973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
31983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
319971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void urlWithSpaceInHost() throws Exception {
320071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    URLConnection urlConnection = client.open(new URL("http://and roid.com/"));
320171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
320271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      urlConnection.getInputStream();
320371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
320471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (UnknownHostException expected) {
320571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
320671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
320771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
320871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void urlWithSpaceInHostViaHttpProxy() throws Exception {
320971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.enqueue(new MockResponse());
321071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    URLConnection urlConnection =
321171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        client.open(new URL("http://and roid.com/"), server.toProxyAddress());
321271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
321371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
321471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      // This test is to check that a NullPointerException is not thrown.
321571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      urlConnection.getInputStream();
321671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail(); // the RI makes a bogus proxy request for "GET http://and roid.com/ HTTP/1.1"
321771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (UnknownHostException expected) {
321871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
321971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
322071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
322171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void urlHostWithNul() throws Exception {
322271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    URLConnection urlConnection = client.open(new URL("http://host\u0000/"));
322371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
322471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      urlConnection.getInputStream();
322571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
322671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (UnknownHostException expected) {
322771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
322871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
322971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
323071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void urlRedirectToHostWithNul() throws Exception {
323171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    String redirectUrl = "http://host\u0000/";
323271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.enqueue(new MockResponse().setResponseCode(302)
323371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller        .addHeaderLenient("Location", redirectUrl));
323471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
323571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    HttpURLConnection urlConnection = client.open(server.getUrl("/"));
323671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(302, urlConnection.getResponseCode());
323771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    assertEquals(redirectUrl, urlConnection.getHeaderField("Location"));
323871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
323971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
324071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Test public void urlWithBadAsciiHost() throws Exception {
324171b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    URLConnection urlConnection = client.open(new URL("http://host\u0001/"));
324271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    try {
324371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      urlConnection.getInputStream();
324471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller      fail();
324571b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    } catch (UnknownHostException expected) {
324671b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    }
324771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  }
324871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller
3249c4c05ff9964ac8bca83bc751abe551f515ca499aNeil Fuller  @Test public void instanceFollowsRedirects() throws Exception {
3250ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    testInstanceFollowsRedirects("http://www.google.com/");
3251ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    testInstanceFollowsRedirects("https://www.google.com/");
3252ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller  }
3253ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller
3254ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller  private void testInstanceFollowsRedirects(String spec) throws Exception {
3255ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    URL url = new URL(spec);
3256ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    HttpURLConnection urlConnection = client.open(url);
3257ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    urlConnection.setInstanceFollowRedirects(true);
3258ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    assertTrue(urlConnection.getInstanceFollowRedirects());
3259ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    urlConnection.setInstanceFollowRedirects(false);
3260ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller    assertFalse(urlConnection.getInstanceFollowRedirects());
3261ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller  }
3262ceafaf318f1176d96d18ed04355f76fa91a8e12bNeil Fuller
326354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /** Returns a gzipped copy of {@code bytes}. */
3264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  public Buffer gzip(String data) throws IOException {
3265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    Buffer result = new Buffer();
3266e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    BufferedSink gzipSink = Okio.buffer(new GzipSink(result));
3267e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    gzipSink.writeUtf8(data);
3268e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    gzipSink.close();
3269e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    return result;
327054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
327154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
327254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  /**
327354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * Reads at most {@code limit} characters from {@code in} and asserts that
327454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   * content equals {@code expected}.
327554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson   */
32763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private void assertContent(String expected, HttpURLConnection connection, int limit)
327754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      throws IOException {
327854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    connection.connect();
327954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertEquals(expected, readAscii(connection.getInputStream(), limit));
328054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
328154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
32823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private void assertContent(String expected, HttpURLConnection connection) throws IOException {
328354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    assertContent(expected, connection, Integer.MAX_VALUE);
328454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
328554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
328654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private Set<String> newSet(String... elements) {
328771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    return new LinkedHashSet<>(Arrays.asList(elements));
328854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
328954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
329054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  enum TransferKind {
329154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    CHUNKED() {
3292e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override void setBody(MockResponse response, Buffer content, int chunkSize)
329354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          throws IOException {
329454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        response.setChunkedBody(content, chunkSize);
329554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
329654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      @Override void setForRequest(HttpURLConnection connection, int contentLength) {
329754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        connection.setChunkedStreamingMode(5);
329854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
329954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    },
330054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    FIXED_LENGTH() {
3301e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override void setBody(MockResponse response, Buffer content, int chunkSize) {
330254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        response.setBody(content);
330354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
330454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      @Override void setForRequest(HttpURLConnection connection, int contentLength) {
3305faf49723fb689c626f69876e718c58018eff8ee7Narayan Kamath        connection.setFixedLengthStreamingMode(contentLength);
330654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
330754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    },
330854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    END_OF_STREAM() {
3309e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override void setBody(MockResponse response, Buffer content, int chunkSize) {
331054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        response.setBody(content);
331154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        response.setSocketPolicy(DISCONNECT_AT_END);
3312e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        response.removeHeader("Content-Length");
331354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
331454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      @Override void setForRequest(HttpURLConnection connection, int contentLength) {
331554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
331654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    };
331754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
3318e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    abstract void setBody(MockResponse response, Buffer content, int chunkSize) throws IOException;
331954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
332054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    abstract void setForRequest(HttpURLConnection connection, int contentLength);
332154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
332254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    void setBody(MockResponse response, String content, int chunkSize) throws IOException {
3323e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      setBody(response, new Buffer().writeUtf8(content), chunkSize);
332454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    }
332554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
332654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
332754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  enum ProxyConfig {
332854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    NO_PROXY() {
3329e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override public HttpURLConnection connect(
3330e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          MockWebServer server, OkUrlFactory streamHandlerFactory, URL url)
333154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          throws IOException {
3332e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        streamHandlerFactory.client().setProxy(Proxy.NO_PROXY);
3333e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        return streamHandlerFactory.open(url);
333454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
333554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    },
333654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson
333754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    CREATE_ARG() {
3338e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override public HttpURLConnection connect(
3339e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          MockWebServer server, OkUrlFactory streamHandlerFactory, URL url)
334054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          throws IOException {
3341e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        streamHandlerFactory.client().setProxy(server.toProxyAddress());
3342e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        return streamHandlerFactory.open(url);
334354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
334454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    },
3345c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
334654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    PROXY_SYSTEM_PROPERTY() {
3347e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override public HttpURLConnection connect(
3348e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          MockWebServer server, OkUrlFactory streamHandlerFactory, URL url)
334954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          throws IOException {
3350e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        System.setProperty("proxyHost", server.getHostName());
335154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        System.setProperty("proxyPort", Integer.toString(server.getPort()));
3352e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        return streamHandlerFactory.open(url);
335354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
335454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    },
3355c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
335654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HTTP_PROXY_SYSTEM_PROPERTY() {
3357e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override public HttpURLConnection connect(
3358e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          MockWebServer server, OkUrlFactory streamHandlerFactory, URL url)
335954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          throws IOException {
3360e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        System.setProperty("http.proxyHost", server.getHostName());
336154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        System.setProperty("http.proxyPort", Integer.toString(server.getPort()));
3362e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        return streamHandlerFactory.open(url);
336354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
336454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    },
3365c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
336654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    HTTPS_PROXY_SYSTEM_PROPERTY() {
3367e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      @Override public HttpURLConnection connect(
3368e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller          MockWebServer server, OkUrlFactory streamHandlerFactory, URL url)
336954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          throws IOException {
3370e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        System.setProperty("https.proxyHost", server.getHostName());
337154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        System.setProperty("https.proxyPort", Integer.toString(server.getPort()));
3372e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        return streamHandlerFactory.open(url);
337354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
337454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    };
3375c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
3376e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    public abstract HttpURLConnection connect(
3377e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        MockWebServer server, OkUrlFactory streamHandlerFactory, URL url)
337854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        throws IOException;
337954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
3380c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
338154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private static class RecordingTrustManager implements X509TrustManager {
338254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    private final List<String> calls = new ArrayList<String>();
33832231db3e6bb54447a9b14cf004a6cb03c373651cjwilson
338454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    public X509Certificate[] getAcceptedIssuers() {
338554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return new X509Certificate[] { };
3386c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
3387c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
338854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    public void checkClientTrusted(X509Certificate[] chain, String authType)
338954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        throws CertificateException {
339054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      calls.add("checkClientTrusted " + certificatesToString(chain));
3391c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
3392c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
339354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    public void checkServerTrusted(X509Certificate[] chain, String authType)
339454cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        throws CertificateException {
339554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      calls.add("checkServerTrusted " + certificatesToString(chain));
3396c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
3397c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath
339854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    private String certificatesToString(X509Certificate[] certificates) {
339954cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      List<String> result = new ArrayList<String>();
340054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      for (X509Certificate certificate : certificates) {
340154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson        result.add(certificate.getSubjectDN() + " " + certificate.getSerialNumber());
340254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      }
340354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return result.toString();
3404c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath    }
340554cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
34067899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
340754cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  private static class FakeProxySelector extends ProxySelector {
3408e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    List<Proxy> proxies = new ArrayList<>();
34097899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath
341054cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    @Override public List<Proxy> select(URI uri) {
341154cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      // Don't handle 'socket' schemes, which the RI's Socket class may request (for SOCKS).
341254cf3446000fdcf88a9e62724f7deb0282e98da1jwilson      return uri.getScheme().equals("http") || uri.getScheme().equals("https") ? proxies
341354cf3446000fdcf88a9e62724f7deb0282e98da1jwilson          : Collections.singletonList(Proxy.NO_PROXY);
34147899c5ab935cf542069835ec7d3e457db596dbf7Narayan Kamath    }
34152231db3e6bb54447a9b14cf004a6cb03c373651cjwilson
341654cf3446000fdcf88a9e62724f7deb0282e98da1jwilson    @Override public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
34172231db3e6bb54447a9b14cf004a6cb03c373651cjwilson    }
341854cf3446000fdcf88a9e62724f7deb0282e98da1jwilson  }
34193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
34203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
34213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Tests that use this will fail unless boot classpath is set. Ex. {@code
3422e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   * -Xbootclasspath/p:/tmp/alpn-boot-8.0.0.v20140317}
3423e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   */
3424e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private void enableProtocol(Protocol protocol) {
3425e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setSslSocketFactory(sslContext.getSocketFactory());
3426e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setHostnameVerifier(new RecordingHostnameVerifier());
3427e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.client().setProtocols(Arrays.asList(protocol, Protocol.HTTP_1_1));
342871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
342971b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.setProtocolNegotiationEnabled(true);
343071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller    server.setProtocols(client.client().getProtocols());
3431e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
3432e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
3433e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  /**
3434e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   * Used during tests that involve TLS connection fallback attempts. OkHttp includes the
3435e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   * TLS_FALLBACK_SCSV cipher on fallback connections. See
3436e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   * {@link com.squareup.okhttp.FallbackTestClientSocketFactory} for details.
34373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
343871b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  private void suppressTlsFallbackScsv(OkHttpClient client) {
3439e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    FallbackTestClientSocketFactory clientSocketFactory =
3440e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        new FallbackTestClientSocketFactory(sslContext.getSocketFactory());
3441e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    client.setSslSocketFactory(clientSocketFactory);
34423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
3443c3f6f16bd4a2338e88275641b9f2f56e816ca377Narayan Kamath}
3444