13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/*
23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Copyright (C) 2013 Square, Inc.
33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *
43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License");
53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * you may not use this file except in compliance with the License.
63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * You may obtain a copy of the License at
73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *
83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *      http://www.apache.org/licenses/LICENSE-2.0
93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller *
103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Unless required by applicable law or agreed to in writing, software
113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS,
123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * See the License for the specific language governing permissions and
143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * limitations under the License.
153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */
163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage com.squareup.okhttp.internal.http;
173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.HttpResponseCache;
193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.OkHttpClient;
203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.Protocol;
213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.RecordingAuthenticator;
223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.SslContextBuilder;
233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.Util;
243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.mockwebserver.MockResponse;
253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.mockwebserver.MockWebServer;
263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.mockwebserver.RecordedRequest;
273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.mockwebserver.SocketPolicy;
283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.ByteArrayOutputStream;
293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.File;
303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.IOException;
313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.InputStream;
323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.io.OutputStream;
333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.net.Authenticator;
343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.net.CookieManager;
353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.net.HttpURLConnection;
363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.net.URL;
373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Arrays;
383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Collection;
393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Collections;
403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.List;
413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Map;
423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.UUID;
433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.concurrent.CountDownLatch;
443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.concurrent.ExecutorService;
453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.concurrent.Executors;
463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.zip.GZIPOutputStream;
473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport javax.net.ssl.HostnameVerifier;
483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport javax.net.ssl.SSLContext;
493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport javax.net.ssl.SSLSession;
503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport org.junit.After;
513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport org.junit.Before;
523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport org.junit.Ignore;
533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport org.junit.Test;
543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static java.util.concurrent.TimeUnit.SECONDS;
563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertArrayEquals;
573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertEquals;
583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertNull;
593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.assertTrue;
603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport static org.junit.Assert.fail;
613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/** Test how SPDY interacts with HTTP features. */
633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpublic abstract class HttpOverSpdyTest {
643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /** Protocol to test, for example {@link com.squareup.okhttp.Protocol#SPDY_3} */
663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private final Protocol protocol;
673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  protected String hostHeader = ":host";
683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  protected HttpOverSpdyTest(Protocol protocol){
703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    this.protocol = protocol;
713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private static final HostnameVerifier NULL_HOSTNAME_VERIFIER = new HostnameVerifier() {
743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    public boolean verify(String hostname, SSLSession session) {
753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      return true;
763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  };
783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private static final SSLContext sslContext = SslContextBuilder.localhost();
803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  protected final MockWebServer server = new MockWebServer();
813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  protected final String hostName = server.getHostName();
823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  protected final OkHttpClient client = new OkHttpClient();
833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  protected HttpURLConnection connection;
843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  protected HttpResponseCache cache;
853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Before public void setUp() throws Exception {
873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.useHttps(sslContext.getSocketFactory(), false);
883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    client.setProtocols(Arrays.asList(protocol, Protocol.HTTP_11));
893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    client.setSslSocketFactory(sslContext.getSocketFactory());
903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    client.setHostnameVerifier(NULL_HOSTNAME_VERIFIER);
913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    String systemTmpDir = System.getProperty("java.io.tmpdir");
923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    File cacheDir = new File(systemTmpDir, "HttpCache-" + protocol + "-" + UUID.randomUUID());
933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE);
943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @After public void tearDown() throws Exception {
973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Authenticator.setDefault(null);
983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.shutdown();
993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void get() throws Exception {
1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    MockResponse response = new MockResponse().setBody("ABCDE").setStatus("HTTP/1.1 200 Sweet");
1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(response);
1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("ABCDE", connection, Integer.MAX_VALUE);
1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(200, connection.getResponseCode());
1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("Sweet", connection.getResponseMessage());
1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request = server.takeRequest();
1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContains(request.getHeaders(), ":scheme: https");
1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContains(request.getHeaders(), hostHeader + ": " + hostName + ":" + server.getPort());
1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void emptyResponse() throws IOException {
1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse());
1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(-1, connection.getInputStream().read());
1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  byte[] postBytes = "FGHIJ".getBytes(Util.UTF_8);
1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /** An output stream can be written to more than once, so we can't guess content length. */
1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void noDefaultContentLengthOnPost() throws Exception {
1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    MockResponse response = new MockResponse().setBody("ABCDE");
1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(response);
1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().write(postBytes);
1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("ABCDE", connection, Integer.MAX_VALUE);
1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request = server.takeRequest();
1393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("POST /foo HTTP/1.1", request.getRequestLine());
1403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertArrayEquals(postBytes, request.getBody());
1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertNull(request.getHeader("Content-Length"));
1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void userSuppliedContentLengthHeader() throws Exception {
1453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    MockResponse response = new MockResponse().setBody("ABCDE");
1463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(response);
1473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
1483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
1503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setRequestProperty("Content-Length", String.valueOf(postBytes.length));
1513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
1523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().write(postBytes);
1533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("ABCDE", connection, Integer.MAX_VALUE);
1543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request = server.takeRequest();
1563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("POST /foo HTTP/1.1", request.getRequestLine());
1573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertArrayEquals(postBytes, request.getBody());
1583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(postBytes.length, Integer.parseInt(request.getHeader("Content-Length")));
1593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void closeAfterFlush() throws Exception {
1623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    MockResponse response = new MockResponse().setBody("ABCDE");
1633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(response);
1643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
1653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
1673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setRequestProperty("Content-Length", String.valueOf(postBytes.length));
1683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
1693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().write(postBytes); // push bytes into SpdyDataOutputStream.buffer
1703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().flush(); // SpdyConnection.writeData subject to write window
1713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().close(); // SpdyConnection.writeData empty frame
1723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("ABCDE", connection, Integer.MAX_VALUE);
1733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request = server.takeRequest();
1753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("POST /foo HTTP/1.1", request.getRequestLine());
1763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertArrayEquals(postBytes, request.getBody());
1773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(postBytes.length, Integer.parseInt(request.getHeader("Content-Length")));
1783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void setFixedLengthStreamingModeSetsContentLength() throws Exception {
1813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    MockResponse response = new MockResponse().setBody("ABCDE");
1823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(response);
1833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
1843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/foo"));
1863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setFixedLengthStreamingMode(postBytes.length);
1873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setDoOutput(true);
1883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.getOutputStream().write(postBytes);
1893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("ABCDE", connection, Integer.MAX_VALUE);
1903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request = server.takeRequest();
1923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("POST /foo HTTP/1.1", request.getRequestLine());
1933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertArrayEquals(postBytes, request.getBody());
1943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(postBytes.length, Integer.parseInt(request.getHeader("Content-Length")));
1953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void spdyConnectionReuse() throws Exception {
1983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("ABCDEF"));
1993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("GHIJKL"));
2003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
2013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection1 = client.open(server.getUrl("/r1"));
2033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection2 = client.open(server.getUrl("/r2"));
2043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("ABC", readAscii(connection1.getInputStream(), 3));
2053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("GHI", readAscii(connection2.getInputStream(), 3));
2063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("DEF", readAscii(connection1.getInputStream(), 3));
2073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("JKL", readAscii(connection2.getInputStream(), 3));
2083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, server.takeRequest().getSequenceNumber());
2093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, server.takeRequest().getSequenceNumber());
2103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
2113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test @Ignore public void synchronousSpdyRequest() throws Exception {
2133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("A"));
2143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("A"));
2153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
2163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    ExecutorService executor = Executors.newCachedThreadPool();
2183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    CountDownLatch countDownLatch = new CountDownLatch(2);
2193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    executor.execute(new SpdyRequest("/r1", countDownLatch));
2203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    executor.execute(new SpdyRequest("/r2", countDownLatch));
2213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    countDownLatch.await();
2223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, server.takeRequest().getSequenceNumber());
2233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, server.takeRequest().getSequenceNumber());
2243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
2253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void gzippedResponseBody() throws Exception {
2273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().addHeader("Content-Encoding: gzip")
2283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setBody(gzip("ABCABCABC".getBytes(Util.UTF_8))));
2293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
2303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("ABCABCABC", client.open(server.getUrl("/r1")), Integer.MAX_VALUE);
2313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
2323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void authenticate() throws Exception {
2343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_UNAUTHORIZED)
2353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("www-authenticate: Basic realm=\"protected area\"")
2363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setBody("Please authenticate."));
2373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("Successful auth!"));
2383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
2393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Authenticator.setDefault(new RecordingAuthenticator());
2413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
2423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
2433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest denied = server.takeRequest();
2453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContainsNoneMatching(denied.getHeaders(), "authorization: Basic .*");
2463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest accepted = server.takeRequest();
2473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("GET / HTTP/1.1", accepted.getRequestLine());
2483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContains(accepted.getHeaders(),
2493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        "authorization: Basic " + RecordingAuthenticator.BASE_64_CREDENTIALS);
2503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
2513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void redirect() throws Exception {
2533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
2543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .addHeader("Location: /foo")
2553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setBody("This page has moved!"));
2563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("This is the new location!"));
2573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
2583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
2603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("This is the new location!", connection, Integer.MAX_VALUE);
2613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request1 = server.takeRequest();
2633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("/", request1.getPath());
2643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest request2 = server.takeRequest();
2653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("/foo", request2.getPath());
2663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
2673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void readAfterLastByte() throws Exception {
2693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("ABC"));
2703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
2713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
2733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    InputStream in = connection.getInputStream();
2743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("ABC", readAscii(in, 3));
2753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(-1, in.read());
2763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(-1, in.read());
2773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
2783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Ignore // See https://github.com/square/okhttp/issues/578
2803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test(timeout = 3000) public void readResponseHeaderTimeout() throws Exception {
2813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.NO_RESPONSE));
2823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("A"));
2833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
2843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
2863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setReadTimeout(1000);
2873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", connection, Integer.MAX_VALUE);
2883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
2893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
2903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
2913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Test to ensure we don't  throw a read timeout on responses that are
2923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * progressing.  For this case, we take a 4KiB body and throttle it to
2933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * 1KiB/second.  We set the read timeout to two seconds.  If our
2943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * implementation is acting correctly, it will not throw, as it is
2953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * progressing.
2963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
2973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void readTimeoutMoreGranularThanBodySize() throws Exception {
2983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    char[] body = new char[4096]; // 4KiB to read
2993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Arrays.fill(body, 'y');
3003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse()
3013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setBody(new String(body))
3023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .throttleBody(1024, 1, SECONDS)); // slow connection 1KiB/second
3033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
3043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
3063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setReadTimeout(2000); // 2 seconds to read something.
3073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent(new String(body), connection, Integer.MAX_VALUE);
3083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
3093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
3113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Test to ensure we throw a read timeout on responses that are progressing
3123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * too slowly.  For this case, we take a 2KiB body and throttle it to
3133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * 1KiB/second.  We set the read timeout to half a second.  If our
3143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * implementation is acting correctly, it will throw, as a byte doesn't
3153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * arrive in time.
3163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
3173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void readTimeoutOnSlowConnection() throws Exception {
3183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    char[] body = new char[2048]; // 2KiB to read
3193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Arrays.fill(body, 'y');
3203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse()
3213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .setBody(new String(body))
3223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        .throttleBody(1024, 1, SECONDS)); // slow connection 1KiB/second
3233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
3243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection = client.open(server.getUrl("/"));
3263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.setReadTimeout(500); // half a second to read something
3273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.connect();
3283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    try {
3293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      readAscii(connection.getInputStream(), Integer.MAX_VALUE);
3303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      fail("Should have timed out!");
3313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    } catch (IOException e){
3323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      assertEquals("Read timed out", e.getMessage());
3333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
3343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
3353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void spdyConnectionTimeout() throws Exception {
3373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    MockResponse response = new MockResponse().setBody("A");
3383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    response.setBodyDelayTimeMs(1000);
3393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(response);
3403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
3413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection1 = client.open(server.getUrl("/"));
3433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection1.setReadTimeout(2000);
3443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection2 = client.open(server.getUrl("/"));
3453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection2.setReadTimeout(200);
3463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection1.connect();
3473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection2.connect();
3483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", connection1, Integer.MAX_VALUE);
3493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
3503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void responsesAreCached() throws IOException {
3523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    client.setOkResponseCache(cache);
3533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().addHeader("cache-control: max-age=60").setBody("A"));
3553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
3563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", client.open(server.getUrl("/")), Integer.MAX_VALUE);
3583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, cache.getRequestCount());
3593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, cache.getNetworkCount());
3603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, cache.getHitCount());
3613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", client.open(server.getUrl("/")), Integer.MAX_VALUE);
3623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", client.open(server.getUrl("/")), Integer.MAX_VALUE);
3633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(3, cache.getRequestCount());
3643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, cache.getNetworkCount());
3653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(2, cache.getHitCount());
3663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
3673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void conditionalCache() throws IOException {
3693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    client.setOkResponseCache(cache);
3703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().addHeader("ETag: v1").setBody("A"));
3723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
3733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
3743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", client.open(server.getUrl("/")), Integer.MAX_VALUE);
3763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, cache.getRequestCount());
3773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, cache.getNetworkCount());
3783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(0, cache.getHitCount());
3793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", client.open(server.getUrl("/")), Integer.MAX_VALUE);
3803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(2, cache.getRequestCount());
3813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(2, cache.getNetworkCount());
3823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(1, cache.getHitCount());
3833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
3843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void responseCachedWithoutConsumingFullBody() throws IOException {
3863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    client.setOkResponseCache(cache);
3873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().addHeader("cache-control: max-age=60").setBody("ABCD"));
3893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().addHeader("cache-control: max-age=60").setBody("EFGH"));
3903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
3913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection1 = client.open(server.getUrl("/"));
3933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    InputStream in1 = connection1.getInputStream();
3943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("AB", readAscii(in1, 2));
3953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    in1.close();
3963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
3973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    HttpURLConnection connection2 = client.open(server.getUrl("/"));
3983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    InputStream in2 = connection2.getInputStream();
3993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals("ABCD", readAscii(in2, Integer.MAX_VALUE));
4003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    in2.close();
4013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  @Test public void acceptAndTransmitCookies() throws Exception {
4043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    CookieManager cookieManager = new CookieManager();
4053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    client.setCookieHandler(cookieManager);
4063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(
4073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        new MockResponse().addHeader("set-cookie: c=oreo; domain=" + server.getCookieDomain())
4083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller            .setBody("A"));
4093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.enqueue(new MockResponse().setBody("B"));
4103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    server.play();
4113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    URL url = server.getUrl("/");
4133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("A", client.open(url), Integer.MAX_VALUE);
4143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Map<String, List<String>> requestHeaders = Collections.emptyMap();
4153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(Collections.singletonMap("Cookie", Arrays.asList("c=oreo")),
4163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        cookieManager.get(url.toURI(), requestHeaders));
4173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContent("B", client.open(url), Integer.MAX_VALUE);
4193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest requestA = server.takeRequest();
4203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContainsNoneMatching(requestA.getHeaders(), "Cookie.*");
4213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    RecordedRequest requestB = server.takeRequest();
4223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertContains(requestB.getHeaders(), "cookie: c=oreo");
4233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  <T> void assertContains(Collection<T> collection, T value) {
4263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertTrue(collection.toString(), collection.contains(value));
4273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  void assertContent(String expected, HttpURLConnection connection, int limit)
4303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      throws IOException {
4313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    connection.connect();
4323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    assertEquals(expected, readAscii(connection.getInputStream(), limit));
4333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private void assertContainsNoneMatching(List<String> headers, String pattern) {
4363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    for (String header : headers) {
4373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (header.matches(pattern)) {
4383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        fail("Header " + header + " matches " + pattern);
4393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
4403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
4413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private String readAscii(InputStream in, int count) throws IOException {
4443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    StringBuilder result = new StringBuilder();
4453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    for (int i = 0; i < count; i++) {
4463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      int value = in.read();
4473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (value == -1) {
4483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        in.close();
4493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        break;
4503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
4513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      result.append((char) value);
4523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
4533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return result.toString();
4543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public byte[] gzip(byte[] bytes) throws IOException {
4573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
4583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    OutputStream gzippedOut = new GZIPOutputStream(bytesOut);
4593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    gzippedOut.write(bytes);
4603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    gzippedOut.close();
4613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return bytesOut.toByteArray();
4623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  class SpdyRequest implements Runnable {
4653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    String path;
4663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    CountDownLatch countDownLatch;
4673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    public SpdyRequest(String path, CountDownLatch countDownLatch) {
4683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      this.path = path;
4693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      this.countDownLatch = countDownLatch;
4703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
4713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
4723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    @Override public void run() {
4733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      try {
4743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        HttpURLConnection conn = client.open(server.getUrl(path));
4753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        assertEquals("A", readAscii(conn.getInputStream(), 1));
4763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        countDownLatch.countDown();
4773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      } catch (Exception e) {
4783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        throw new RuntimeException(e);
4793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
4803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
4813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
4823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller}
483