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