URLConnectionTest.java revision a468471e8ccc2f642d5b2ae3c75873a74267ece2
10c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson/* 20c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Copyright (C) 2009 The Android Open Source Project 30c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 40c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 50c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * you may not use this file except in compliance with the License. 60c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * You may obtain a copy of the License at 70c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 80c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 90c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Unless required by applicable law or agreed to in writing, software 110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * See the License for the specific language governing permissions and 140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * limitations under the License. 150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 17757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilsonpackage libcore.java.net; 180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport com.google.mockwebserver.MockResponse; 200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport com.google.mockwebserver.MockWebServer; 21433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport com.google.mockwebserver.RecordedRequest; 22c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilsonimport com.google.mockwebserver.SocketPolicy; 230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_END; 240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_START; 250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport static com.google.mockwebserver.SocketPolicy.SHUTDOWN_INPUT_AT_END; 260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport static com.google.mockwebserver.SocketPolicy.SHUTDOWN_OUTPUT_AT_END; 270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.ByteArrayOutputStream; 280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.IOException; 290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.InputStream; 300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.io.OutputStream; 310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.Authenticator; 320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheRequest; 330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.CacheResponse; 340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.ConnectException; 350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.HttpRetryException; 360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.HttpURLConnection; 370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.PasswordAuthentication; 38953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.net.ProtocolException; 39953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.net.Proxy; 400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.ResponseCache; 410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.SocketTimeoutException; 420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URI; 430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URL; 440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.net.URLConnection; 450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.security.cert.CertificateException; 46953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.security.cert.X509Certificate; 470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.ArrayList; 48953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilsonimport java.util.Arrays; 49433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport java.util.Collections; 500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.HashSet; 510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Iterator; 520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.List; 530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Map; 540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.Set; 550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicBoolean; 560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.concurrent.atomic.AtomicReference; 570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.zip.GZIPInputStream; 580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport java.util.zip.GZIPOutputStream; 590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.HostnameVerifier; 600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.HttpsURLConnection; 610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.SSLContext; 62396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilsonimport javax.net.ssl.SSLException; 630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.SSLHandshakeException; 64396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilsonimport javax.net.ssl.SSLSession; 650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.SSLSocketFactory; 660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.TrustManager; 670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonimport javax.net.ssl.X509TrustManager; 68433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport junit.framework.TestCase; 69433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport libcore.java.security.TestKeyStore; 70433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport libcore.javax.net.ssl.TestSSLContext; 71433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilsonimport tests.net.StuckServer; 72396af46f45fd302e6309fc48ac1fd68cbb739edbJesse Wilson 730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilsonpublic final class URLConnectionTest extends TestCase { 740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private static final Authenticator SIMPLE_AUTHENTICATOR = new Authenticator() { 760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson protected PasswordAuthentication getPasswordAuthentication() { 770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return new PasswordAuthentication("username", "password".toCharArray()); 78433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } 79433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson }; 800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** base64("username:password") */ 820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private static final String BASE_64_CREDENTIALS = "dXNlcm5hbWU6cGFzc3dvcmQ="; 830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private MockWebServer server = new MockWebServer(); 850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String hostName; 860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson @Override protected void setUp() throws Exception { 880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson super.setUp(); 890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson hostName = server.getHostName(); 900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson @Override protected void tearDown() throws Exception { 930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson ResponseCache.setDefault(null); 940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Authenticator.setDefault(null); 950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson System.clearProperty("proxyHost"); 960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson System.clearProperty("proxyPort"); 970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson System.clearProperty("http.proxyHost"); 980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson System.clearProperty("http.proxyPort"); 990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson System.clearProperty("https.proxyHost"); 1000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson System.clearProperty("https.proxyPort"); 1010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.shutdown(); 1020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson super.tearDown(); 10384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 1040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testRequestHeaders() throws IOException, InterruptedException { 1060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse()); 1070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 1100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("D", "e"); 1110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("D", "f"); 1120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("f", urlConnection.getRequestProperty("D")); 1130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("f", urlConnection.getRequestProperty("d")); 1140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> requestHeaders = urlConnection.getRequestProperties(); 1150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(newSet("e", "f"), new HashSet<String>(requestHeaders.get("D"))); 1160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(newSet("e", "f"), new HashSet<String>(requestHeaders.get("d"))); 1170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestHeaders.put("G", Arrays.asList("h")); 1190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Modified an unmodifiable view."); 1200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (UnsupportedOperationException expected) { 1210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson requestHeaders.get("D").add("i"); 1240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Modified an unmodifiable view."); 1250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (UnsupportedOperationException expected) { 1260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.setRequestProperty(null, "j"); 1290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 1300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (NullPointerException expected) { 1310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty(null, "k"); 1340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 1350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (NullPointerException expected) { 1360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.setRequestProperty("NullValue", null); // should fail silently! 1380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNull(urlConnection.getRequestProperty("NullValue")); 1390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("AnotherNullValue", null); // should fail silently! 1400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNull(urlConnection.getRequestProperty("AnotherNullValue")); 1410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson urlConnection.getResponseCode(); 1430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 1440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(request.getHeaders(), "D: e"); 1450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(request.getHeaders(), "D: f"); 1460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContainsNoneMatching(request.getHeaders(), "NullValue.*"); 1470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContainsNoneMatching(request.getHeaders(), "AnotherNullValue.*"); 1480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContainsNoneMatching(request.getHeaders(), "G:.*"); 1490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContainsNoneMatching(request.getHeaders(), "null:.*"); 1500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("N", "o"); 1530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Set header after connect"); 1540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IllegalStateException expected) { 1550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 1570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.setRequestProperty("P", "q"); 1580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Set header after connect"); 1590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IllegalStateException expected) { 16084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 1610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 162433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson urlConnection.getRequestProperties(); 163433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson fail(); 164433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } catch (IllegalStateException expected) { 165433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } 166433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } 167433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson 168433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson public void testGetRequestPropertyReturnsLastValue() throws Exception { 169433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson server.play(); 1700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 1710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("A", "value1"); 1720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.addRequestProperty("A", "value2"); 1730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("value2", urlConnection.getRequestProperty("A")); 1740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 1750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponseHeaders() throws IOException, InterruptedException { 1770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 1780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setStatus("HTTP/1.0 200 Fantastic") 1790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("A: c") 1800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("B: d") 1810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("A: e") 1820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setChunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8)); 1830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 1840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 1850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 1860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, urlConnection.getResponseCode()); 1870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Fantastic", urlConnection.getResponseMessage()); 1880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("HTTP/1.0 200 Fantastic", urlConnection.getHeaderField(null)); 1890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson Map<String, List<String>> responseHeaders = urlConnection.getHeaderFields(); 1900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("HTTP/1.0 200 Fantastic"), responseHeaders.get(null)); 1910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(newSet("c", "e"), new HashSet<String>(responseHeaders.get("A"))); 1920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(newSet("c", "e"), new HashSet<String>(responseHeaders.get("a"))); 1930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 194953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson responseHeaders.put("N", Arrays.asList("o")); 195953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail("Modified an unmodifiable view."); 196953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (UnsupportedOperationException expected) { 197953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 198953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson try { 199953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson responseHeaders.get("A").add("f"); 200953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail("Modified an unmodifiable view."); 201953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } catch (UnsupportedOperationException expected) { 202953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 203953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", urlConnection.getHeaderFieldKey(0)); 2040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("c", urlConnection.getHeaderField(0)); 2050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("B", urlConnection.getHeaderFieldKey(1)); 2060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("d", urlConnection.getHeaderField(1)); 2070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("A", urlConnection.getHeaderFieldKey(2)); 2080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("e", urlConnection.getHeaderField(2)); 2090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testGetErrorStreamOnSuccessfulRequest() throws Exception { 2120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A")); 2130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 2150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNull(connection.getErrorStream()); 2160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testGetErrorStreamOnUnsuccessfulRequest() throws Exception { 2190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setResponseCode(404).setBody("A")); 2200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 222953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("A", readAscii(connection.getErrorStream(), Integer.MAX_VALUE)); 2230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Check that if we don't read to the end of a response, the next request on the 2260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // recycled connection doesn't get the unread tail of the first request's response. 2270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // http://code.google.com/p/android/issues/detail?id=2939 2280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_2939() throws Exception { 2290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse().setChunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8); 2300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("ABCDE", server.getUrl("/").openConnection(), 5); 2360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("ABCDE", server.getUrl("/").openConnection(), 5); 2370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Check that we recognize a few basic mime types by extension. 2400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // http://code.google.com/p/android/issues/detail?id=10100 2410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_10100() throws Exception { 2420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("image/jpeg", URLConnection.guessContentTypeFromName("someFile.jpg")); 2430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("application/pdf", URLConnection.guessContentTypeFromName("stuff.pdf")); 2440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectionsArePooled() throws Exception { 2470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse().setBody("ABCDEFGHIJKLMNOPQR"); 2480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/foo").openConnection()); 2550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 2560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/bar?baz=quux").openConnection()); 2570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 2580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/z").openConnection()); 2590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(2, server.takeRequest().getSequenceNumber()); 2600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 261ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson 262ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson public void testChunkedConnectionsArePooled() throws Exception { 2630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse().setChunkedBody("ABCDEFGHIJKLMNOPQR", 5); 2640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 2680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/foo").openConnection()); 2710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 272433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/bar?baz=quux").openConnection()); 273ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 274ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/z").openConnection()); 275ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(2, server.takeRequest().getSequenceNumber()); 276ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson } 2770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerClosesSocket() throws Exception { 2790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerClosesOutput(DISCONNECT_AT_END); 2800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerShutdownInput() throws Exception { 2830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerClosesOutput(SHUTDOWN_INPUT_AT_END); 2840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testServerShutdownOutput() throws Exception { 2870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testServerClosesOutput(SHUTDOWN_OUTPUT_AT_END); 2880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 2890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testServerClosesOutput(SocketPolicy socketPolicy) throws Exception { 2910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 2920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("This connection won't pool properly") 2930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setSocketPolicy(socketPolicy)); 2940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 2950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("This comes after a busted connection")); 2960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 2970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 2980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("This connection won't pool properly", server.getUrl("/a").openConnection()); 2990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 3000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("This comes after a busted connection", server.getUrl("/b").openConnection()); 3010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // sequence number 0 means the HTTP socket connection was not reused 3020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 303ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson } 304ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson 305ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson enum WriteKind { BYTE_BY_BYTE, SMALL_BUFFERS, LARGE_BUFFERS } 3060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_chunkedUpload_byteByByte() throws Exception { 3080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson doUpload(TransferKind.CHUNKED, WriteKind.BYTE_BY_BYTE); 3090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_chunkedUpload_smallBuffers() throws Exception { 3120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson doUpload(TransferKind.CHUNKED, WriteKind.SMALL_BUFFERS); 3130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_chunkedUpload_largeBuffers() throws Exception { 3160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson doUpload(TransferKind.CHUNKED, WriteKind.LARGE_BUFFERS); 3170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_fixedLengthUpload_byteByByte() throws Exception { 3200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson doUpload(TransferKind.FIXED_LENGTH, WriteKind.BYTE_BY_BYTE); 3210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_fixedLengthUpload_smallBuffers() throws Exception { 3240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson doUpload(TransferKind.FIXED_LENGTH, WriteKind.SMALL_BUFFERS); 3250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void test_fixedLengthUpload_largeBuffers() throws Exception { 3280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson doUpload(TransferKind.FIXED_LENGTH, WriteKind.LARGE_BUFFERS); 3290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Exception { 332a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson int n = 512*1024; 3330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.setBodyLimit(0); 3340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse()); 3350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) server.getUrl("/").openConnection(); 3380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson conn.setDoOutput(true); 3390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson conn.setRequestMethod("POST"); 3400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (uploadKind == TransferKind.CHUNKED) { 3410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson conn.setChunkedStreamingMode(-1); 3420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } else { 3430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson conn.setFixedLengthStreamingMode(n); 3440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 345953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson OutputStream out = conn.getOutputStream(); 3460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (writeKind == WriteKind.BYTE_BY_BYTE) { 3470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 0; i < n; ++i) { 348953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson out.write('x'); 3490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } else { 351ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson byte[] buf = new byte[writeKind == WriteKind.SMALL_BUFFERS ? 256 : 64*1024]; 352ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson Arrays.fill(buf, (byte) 'x'); 353ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson for (int i = 0; i < n; i += buf.length) { 3540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson out.write(buf, 0, Math.min(buf.length, n - i)); 3550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 356a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } 357a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson out.close(); 358a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(200, conn.getResponseCode()); 359a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson RecordedRequest request = server.takeRequest(); 360a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(n, request.getBodySize()); 361a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson if (uploadKind == TransferKind.CHUNKED) { 362a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertTrue(request.getChunkSizes().size() > 0); 363a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } else { 364a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertTrue(request.getChunkSizes().isEmpty()); 365a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } 366a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } 367a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 368a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson public void testGetResponseCodeNoResponseBody() throws Exception { 369a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.enqueue(new MockResponse() 370a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson .addHeader("abc: def")); 371a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson server.play(); 372a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson 373a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson URL url = server.getUrl("/"); 374a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 375a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson conn.setDoInput(false); 376a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals("def", conn.getHeaderField("abc")); 377a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson assertEquals(200, conn.getResponseCode()); 378a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson try { 379a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson conn.getInputStream(); 380a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson fail(); 381a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } catch (ProtocolException expected) { 382a4193d7e636802a2705ffb52cb69c69ff59bfbb2Jesse Wilson } 3830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 3840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectViaHttps() throws IOException, InterruptedException { 3860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 3870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 3890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); 3900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 3910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/foo").openConnection(); 3930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 3940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("this response comes via HTTPS", connection); 3960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 3970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 3980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("GET /foo HTTP/1.1", request.getRequestLine()); 3990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectViaHttpsReusingConnections() throws IOException, InterruptedException { 4020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 4030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 4050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); 406ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.enqueue(new MockResponse().setBody("another response via HTTPS")); 407ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.play(); 4080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 4100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("this response comes via HTTPS", connection); 4120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 4140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("another response via HTTPS", connection); 4160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 4180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 4190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectViaHttpsReusingConnectionsDifferentFactories() 4220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson throws IOException, InterruptedException { 4230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 4240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 4260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); 4270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("another response via HTTPS")); 4280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // install a custom SSL socket factory so the server can be authorized 4310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 4320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("this response comes via HTTPS", connection); 4340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 4360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE); 4380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("without an SSL socket factory, the connection should fail"); 4390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (SSLException expected) { 4400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectViaHttpsWithSSLFallback() throws IOException, InterruptedException { 4440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 4450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 4470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setSocketPolicy(DISCONNECT_AT_START)); 4480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("this response comes via SSL")); 4490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/foo").openConnection(); 4520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("this response comes via SSL", connection); 4550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 4570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("GET /foo HTTP/1.1", request.getRequestLine()); 4580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 4610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Verify that we don't retry connections on certificate verification errors. 4620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * 4630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://code.google.com/p/android/issues/detail?id=13178 4640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 465433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson public void testConnectViaHttpsToUntrustedServer() throws IOException, InterruptedException { 466433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(TestKeyStore.getClientCA2(), 4670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestKeyStore.getServer()); 4680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 469ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 470ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.enqueue(new MockResponse()); // unused 4710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 4720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 473ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/foo").openConnection(); 474ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 4750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 4760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.getInputStream(); 4770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 4780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (SSLHandshakeException expected) { 4790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(expected.getCause() instanceof CertificateException); 4800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.getRequestCount()); 4820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectViaProxyUsingProxyArg() throws Exception { 4850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testConnectViaProxy(ProxyConfig.CREATE_ARG); 4860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectViaProxyUsingProxySystemProperty() throws Exception { 4890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testConnectViaProxy(ProxyConfig.PROXY_SYSTEM_PROPERTY); 4900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectViaProxyUsingHttpProxySystemProperty() throws Exception { 4930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testConnectViaProxy(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY); 4940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 4950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 4960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testConnectViaProxy(ProxyConfig proxyConfig) throws Exception { 4970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse mockResponse = new MockResponse().setBody("this response comes via a proxy"); 4980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(mockResponse); 4990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 5000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = new URL("http://android.com/foo"); 5020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection connection = proxyConfig.connect(server, url); 5030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("this response comes via a proxy", connection); 5040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 506ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals("GET http://android.com/foo HTTP/1.1", request.getRequestLine()); 507ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertContains(request.getHeaders(), "Host: android.com"); 5080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 50984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 510ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson public void testContentDisagreesWithContentLengthHeader() throws IOException { 511ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.enqueue(new MockResponse() 5120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("abc\r\nYOU SHOULD NOT SEE THIS") 5130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .clearHeaders() 514953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("Content-Length: 3")); 51521dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 51621dddca4064527116af7a1553de502c6d11138daJesse Wilson 51721dddca4064527116af7a1553de502c6d11138daJesse Wilson assertContent("abc", server.getUrl("/").openConnection()); 51821dddca4064527116af7a1553de502c6d11138daJesse Wilson } 519953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 52021dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testContentDisagreesWithChunkedHeader() throws IOException { 521953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson MockResponse mockResponse = new MockResponse(); 522953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson mockResponse.setChunkedBody("abc", 3); 523953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 524953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson bytesOut.write(mockResponse.getBody()); 525953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson bytesOut.write("\r\nYOU SHOULD NOT SEE THIS".getBytes()); 526953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson mockResponse.setBody(bytesOut.toByteArray()); 527953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson mockResponse.clearHeaders(); 528953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson mockResponse.addHeader("Transfer-encoding: chunked"); 529953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 53021dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(mockResponse); 53121dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 53221dddca4064527116af7a1553de502c6d11138daJesse Wilson 53321dddca4064527116af7a1553de502c6d11138daJesse Wilson assertContent("abc", server.getUrl("/").openConnection()); 53421dddca4064527116af7a1553de502c6d11138daJesse Wilson } 53521dddca4064527116af7a1553de502c6d11138daJesse Wilson 53621dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testConnectViaHttpProxyToHttpsUsingProxyArgWithNoProxy() throws Exception { 53721dddca4064527116af7a1553de502c6d11138daJesse Wilson testConnectViaDirectProxyToHttps(ProxyConfig.NO_PROXY); 5380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 53921dddca4064527116af7a1553de502c6d11138daJesse Wilson 54021dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testConnectViaHttpProxyToHttpsUsingHttpProxySystemProperty() throws Exception { 5410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // https should not use http proxy 5420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testConnectViaDirectProxyToHttps(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY); 5430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 545953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson private void testConnectViaDirectProxyToHttps(ProxyConfig proxyConfig) throws Exception { 546953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 547953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 548953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 549953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("this response comes via HTTPS")); 550953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 551953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 552953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URL url = server.getUrl("/foo"); 553953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) proxyConfig.connect(server, url); 554953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 555953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 556953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertContent("this response comes via HTTPS", connection); 557953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 558953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson RecordedRequest request = server.takeRequest(); 559953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("GET /foo HTTP/1.1", request.getRequestLine()); 560953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 561953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 562953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 56321dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testConnectViaHttpProxyToHttpsUsingProxyArg() throws Exception { 56421dddca4064527116af7a1553de502c6d11138daJesse Wilson testConnectViaHttpProxyToHttps(ProxyConfig.CREATE_ARG); 56521dddca4064527116af7a1553de502c6d11138daJesse Wilson } 56621dddca4064527116af7a1553de502c6d11138daJesse Wilson 56721dddca4064527116af7a1553de502c6d11138daJesse Wilson /** 56821dddca4064527116af7a1553de502c6d11138daJesse Wilson * We weren't honoring all of the appropriate proxy system properties when 56921dddca4064527116af7a1553de502c6d11138daJesse Wilson * connecting via HTTPS. http://b/3097518 57021dddca4064527116af7a1553de502c6d11138daJesse Wilson */ 57121dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testConnectViaHttpProxyToHttpsUsingProxySystemProperty() throws Exception { 57221dddca4064527116af7a1553de502c6d11138daJesse Wilson testConnectViaHttpProxyToHttps(ProxyConfig.PROXY_SYSTEM_PROPERTY); 57321dddca4064527116af7a1553de502c6d11138daJesse Wilson } 57421dddca4064527116af7a1553de502c6d11138daJesse Wilson 57521dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testConnectViaHttpProxyToHttpsUsingHttpsProxySystemProperty() throws Exception { 5760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testConnectViaHttpProxyToHttps(ProxyConfig.HTTPS_PROXY_SYSTEM_PROPERTY); 5770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 5780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 5800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * We were verifying the wrong hostname when connecting to an HTTPS site 5810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * through a proxy. http://b/3097277 5820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 5830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception { 5840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 5850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); 5860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), true); 5880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 5890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) 5900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .clearHeaders()); 5910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("this response comes via a secure proxy")); 5920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 5930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = new URL("https://android.com/foo"); 5950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) proxyConfig.connect(server, url); 5960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 5970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setHostnameVerifier(hostnameVerifier); 5980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 5990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("this response comes via a secure proxy", connection); 6000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest connect = server.takeRequest(); 6020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Connect line failure on proxy", 6030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson "CONNECT android.com:443 HTTP/1.1", connect.getRequestLine()); 6040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(connect.getHeaders(), "Host: android.com"); 6050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest get = server.takeRequest(); 6070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("GET /foo HTTP/1.1", get.getRequestLine()); 6080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(get.getHeaders(), "Host: android.com"); 6090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("verify android.com"), hostnameVerifier.calls); 6100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 61384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * Test which headers are sent unencrypted to the HTTP proxy. 61484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson */ 61584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testProxyConnectIncludesProxyHeadersOnly() 61684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson throws IOException, InterruptedException { 6170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); 6180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 6190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), true); 6210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 6220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) 6230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .clearHeaders()); 6240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("encrypted response from the origin server")); 6250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 6260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = new URL("https://android.com/foo"); 6280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) url.openConnection( 6290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.toProxyAddress()); 6300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.addRequestProperty("Private", "Secret"); 6310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.addRequestProperty("Proxy-Authorization", "bar"); 6320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.addRequestProperty("User-Agent", "baz"); 633adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 634adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.setHostnameVerifier(hostnameVerifier); 635adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertContent("encrypted response from the origin server", connection); 636adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 637adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson RecordedRequest connect = server.takeRequest(); 638adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertContainsNoneMatching(connect.getHeaders(), "Private.*"); 639adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertContains(connect.getHeaders(), "Proxy-Authorization: bar"); 640adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertContains(connect.getHeaders(), "User-Agent: baz"); 641adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertContains(connect.getHeaders(), "Host: android.com"); 642adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertContains(connect.getHeaders(), "Proxy-Connection: Keep-Alive"); 643adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 644adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson RecordedRequest get = server.takeRequest(); 645adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertContains(get.getHeaders(), "Private: Secret"); 64621dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals(Arrays.asList("verify android.com"), hostnameVerifier.calls); 64721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 64821dddca4064527116af7a1553de502c6d11138daJesse Wilson 64921dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testProxyAuthenticateOnConnect() throws Exception { 65021dddca4064527116af7a1553de502c6d11138daJesse Wilson Authenticator.setDefault(SIMPLE_AUTHENTICATOR); 65121dddca4064527116af7a1553de502c6d11138daJesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 65221dddca4064527116af7a1553de502c6d11138daJesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), true); 65321dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 65421dddca4064527116af7a1553de502c6d11138daJesse Wilson .setResponseCode(407) 65521dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("Proxy-Authenticate: Basic realm=\"localhost\"")); 65621dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse() 65721dddca4064527116af7a1553de502c6d11138daJesse Wilson .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END) 65821dddca4064527116af7a1553de502c6d11138daJesse Wilson .clearHeaders()); 65921dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("A")); 6600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 6610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = new URL("https://android.com/foo"); 6630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) url.openConnection( 6640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.toProxyAddress()); 6650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 6660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setHostnameVerifier(new RecordingHostnameVerifier()); 6670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("A", connection); 6680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest connect1 = server.takeRequest(); 6700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("CONNECT android.com:443 HTTP/1.1", connect1.getRequestLine()); 6710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContainsNoneMatching(connect1.getHeaders(), "Proxy\\-Authorization.*"); 6720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest connect2 = server.takeRequest(); 6740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("CONNECT android.com:443 HTTP/1.1", connect2.getRequestLine()); 6750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(connect2.getHeaders(), "Proxy-Authorization: Basic " + BASE_64_CREDENTIALS); 6760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest get = server.takeRequest(); 6780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("GET /foo HTTP/1.1", get.getRequestLine()); 6790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContainsNoneMatching(get.getHeaders(), "Proxy\\-Authorization.*"); 6800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testDisconnectedConnection() throws IOException { 6830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABCDEFGHIJKLMNOPQR")); 6840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 6850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 6870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = connection.getInputStream(); 6880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals('A', (char) in.read()); 6890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.disconnect(); 6900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 6910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.read(); 6920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail("Expected a connection closed exception"); 6930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 6940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 6960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 6970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testDisconnectBeforeConnect() throws IOException { 6980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("A")); 6990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 7020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.disconnect(); 7030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("A", connection); 7050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, connection.getResponseCode()); 7060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testDefaultRequestProperty() throws Exception { 709953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson URLConnection.setDefaultRequestProperty("X-testSetDefaultRequestProperty", "A"); 7100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNull(URLConnection.getDefaultRequestProperty("X-setDefaultRequestProperty")); 7110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 7140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Reads {@code count} characters from the stream. If the stream is 7150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * exhausted before {@code count} characters can be read, the remaining 7160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * characters are returned and the stream is closed. 7170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private String readAscii(InputStream in, int count) throws IOException { 7190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson StringBuilder result = new StringBuilder(); 7200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson for (int i = 0; i < count; i++) { 7210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson int value = in.read(); 7220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson if (value == -1) { 7230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.close(); 7240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson break; 7250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson result.append((char) value); 7270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson return result.toString(); 7290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMarkAndResetWithContentLengthHeader() throws IOException { 7320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMarkAndReset(TransferKind.FIXED_LENGTH); 7330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMarkAndResetWithChunkedEncoding() throws IOException { 7360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMarkAndReset(TransferKind.CHUNKED); 7370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMarkAndResetWithNoLengthHeaders() throws IOException { 7400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testMarkAndReset(TransferKind.END_OF_STREAM); 7410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testMarkAndReset(TransferKind transferKind) throws IOException { 7440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse(); 7450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson transferKind.setBody(response, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1024); 7460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 7470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 7480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = server.getUrl("/").openConnection().getInputStream(); 7510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertFalse("This implementation claims to support mark().", in.markSupported()); 7520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.mark(5); 7530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", readAscii(in, 5)); 7540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 7550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.reset(); 7560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 7570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException expected) { 7580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("FGHIJKLMNOPQRSTUVWXYZ", readAscii(in, Integer.MAX_VALUE)); 7600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQRSTUVWXYZ", server.getUrl("/").openConnection()); 7610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 7640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * We've had a bug where we forget the HTTP response when we see response 7650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * code 401. This causes a new HTTP request to be issued for every call into 7660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * the URLConnection. 7670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 7680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testUnauthorizedResponseHandling() throws IOException { 7690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse response = new MockResponse() 7700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("WWW-Authenticate: challenge") 7710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(401) // UNAUTHORIZED 7720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("Unauthorized"); 7730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 7740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 7750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(response); 7760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 7790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 7800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(401, conn.getResponseCode()); 7820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(401, conn.getResponseCode()); 7830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(401, conn.getResponseCode()); 7840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, server.getRequestCount()); 7850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 7860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testNonHexChunkSize() throws IOException { 7880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 7890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("5\r\nABCDE\r\nG\r\nFGHIJKLMNOPQRSTU\r\n0\r\n\r\n") 7900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .clearHeaders() 7910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Transfer-encoding: chunked")); 7920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 7930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 7940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 7950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 7960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE); 7970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 7980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException e) { 7990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testMissingChunkBody() throws IOException { 8030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 8040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("5") 8050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .clearHeaders() 8060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Transfer-encoding: chunked") 8070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setSocketPolicy(DISCONNECT_AT_END)); 8080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 8110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 8120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE); 8130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 8140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (IOException e) { 8150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 8190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * This test checks whether connections are gzipped by default. This 8200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * behavior in not required by the API, so a failure of this test does not 8210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * imply a bug in the implementation. 8220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 8230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testGzipEncodingEnabledByDefault() throws IOException, InterruptedException { 8240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 8250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(gzip("ABCABCABC".getBytes("UTF-8"))) 8260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Encoding: gzip")); 8270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 8300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCABCABC", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 8310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertNull(connection.getContentEncoding()); 8320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 8340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(request.getHeaders(), "Accept-Encoding: gzip"); 8350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientConfiguredGzipContentEncoding() throws Exception { 8380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 8390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody(gzip("ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes("UTF-8"))) 8400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Encoding: gzip")); 8410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 8440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.addRequestProperty("Accept-Encoding", "gzip"); 8450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream gunzippedIn = new GZIPInputStream(connection.getInputStream()); 8460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", readAscii(gunzippedIn, Integer.MAX_VALUE)); 8470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 8490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(request.getHeaders(), "Accept-Encoding: gzip"); 8500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testGzipAndConnectionReuseWithFixedLength() throws Exception { 8530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.FIXED_LENGTH); 8540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testGzipAndConnectionReuseWithChunkedEncoding() throws Exception { 8570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testClientConfiguredGzipContentEncodingAndConnectionReuse(TransferKind.CHUNKED); 8580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testClientConfiguredCustomContentEncoding() throws Exception { 8610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 8620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABCDE") 8630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Encoding: custom")); 8640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 8650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 8670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.addRequestProperty("Accept-Encoding", "custom"); 8680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABCDE", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 8690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 8710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(request.getHeaders(), "Accept-Encoding: custom"); 8720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 8730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 8740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /** 8750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * Test a bug where gzip input streams weren't exhausting the input stream, 8760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * which corrupted the request that followed. 8770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * http://code.google.com/p/android/issues/detail?id=7059 8780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 8790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testClientConfiguredGzipContentEncodingAndConnectionReuse( 880adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson TransferKind transferKind) throws Exception { 881adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson MockResponse responseOne = new MockResponse(); 882adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson responseOne.addHeader("Content-Encoding: gzip"); 883adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson transferKind.setBody(responseOne, gzip("one (gzipped)".getBytes("UTF-8")), 5); 884adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(responseOne); 885adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson MockResponse responseTwo = new MockResponse(); 886adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson transferKind.setBody(responseTwo, "two (identity)", 5); 887adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(responseTwo); 888adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.play(); 889adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 890adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 891adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection.addRequestProperty("Accept-Encoding", "gzip"); 892adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson InputStream gunzippedIn = new GZIPInputStream(connection.getInputStream()); 893adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("one (gzipped)", readAscii(gunzippedIn, Integer.MAX_VALUE)); 894adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 895adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 896adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson connection = server.getUrl("/").openConnection(); 897adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals("two (identity)", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 898adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 899adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson } 900adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson 901adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson /** 902adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson * Obnoxiously test that the chunk sizes transmitted exactly equal the 903adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson * requested data+chunk header size. Although setChunkedStreamingMode() 904adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson * isn't specific about whether the size applies to the data or the 905adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson * complete chunk, the RI interprets it as a complete chunk. 906adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson */ 907adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson public void testSetChunkedStreamingMode() throws IOException, InterruptedException { 908adb64fbba2b781467e055706c3de0873dfc01166Jesse Wilson server.enqueue(new MockResponse()); 909c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 910c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 911c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 912c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson urlConnection.setChunkedStreamingMode(8); 913c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson urlConnection.setDoOutput(true); 914c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson OutputStream outputStream = urlConnection.getOutputStream(); 915c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson outputStream.write("ABCDEFGHIJKLMNOPQ".getBytes("US-ASCII")); 916c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals(200, urlConnection.getResponseCode()); 917c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 918c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson RecordedRequest request = server.takeRequest(); 919c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals("ABCDEFGHIJKLMNOPQ", new String(request.getBody(), "US-ASCII")); 920c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals(Arrays.asList(3, 3, 3, 3, 3, 2), request.getChunkSizes()); 921953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 922953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 923c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testAuthenticateWithFixedLengthStreaming() throws Exception { 924c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson testAuthenticateWithStreamingPost(StreamingMode.FIXED_LENGTH); 9252f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 9262f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 9272f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson public void testAuthenticateWithChunkedStreaming() throws Exception { 9282f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson testAuthenticateWithStreamingPost(StreamingMode.CHUNKED); 9292f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 9302f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 9312f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson private void testAuthenticateWithStreamingPost(StreamingMode streamingMode) throws Exception { 9322f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson MockResponse pleaseAuthenticate = new MockResponse() 9332f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .setResponseCode(401) 9342f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("WWW-Authenticate: Basic realm=\"protected area\"") 9352f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .setBody("Please authenticate."); 9362f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(pleaseAuthenticate); 9372f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.play(); 9382f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 939c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson Authenticator.setDefault(SIMPLE_AUTHENTICATOR); 940c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 941c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.setDoOutput(true); 942c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson byte[] requestBody = { 'A', 'B', 'C', 'D' }; 943953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson if (streamingMode == StreamingMode.FIXED_LENGTH) { 944c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.setFixedLengthStreamingMode(requestBody.length); 945c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } else if (streamingMode == StreamingMode.CHUNKED) { 946c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.setChunkedStreamingMode(0); 947c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 948c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson OutputStream outputStream = connection.getOutputStream(); 949c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson outputStream.write(requestBody); 950c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson outputStream.close(); 951c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson try { 952c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.getInputStream(); 953c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson fail(); 954c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } catch (HttpRetryException expected) { 955c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 956c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 957c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson // no authorization header for the request... 958c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson RecordedRequest request = server.takeRequest(); 959c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertContainsNoneMatching(request.getHeaders(), "Authorization: Basic .*"); 960c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertEquals(Arrays.toString(requestBody), Arrays.toString(request.getBody())); 961c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 962c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 963c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testSetValidRequestMethod() throws Exception { 964c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 965c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertValidRequestMethod("GET"); 966c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertValidRequestMethod("DELETE"); 967953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertValidRequestMethod("HEAD"); 968c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertValidRequestMethod("OPTIONS"); 969c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertValidRequestMethod("POST"); 970c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertValidRequestMethod("PUT"); 971c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertValidRequestMethod("TRACE"); 972c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 973c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 974c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson private void assertValidRequestMethod(String requestMethod) throws Exception { 975c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 976c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.setRequestMethod(requestMethod); 977953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(requestMethod, connection.getRequestMethod()); 978c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } 979c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 980c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testSetInvalidRequestMethodLowercase() throws Exception { 981c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson server.play(); 98284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertInvalidRequestMethod("get"); 98384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 98484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 98584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testSetInvalidRequestMethodConnect() throws Exception { 98684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 98784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertInvalidRequestMethod("CONNECT"); 98884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 98984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 99084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson private void assertInvalidRequestMethod(String requestMethod) throws Exception { 99184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 99284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson try { 99384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setRequestMethod(requestMethod); 99484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson fail(); 99584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } catch (ProtocolException expected) { 99684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 99784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 99884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 99984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testCannotSetNegativeFixedLengthStreamingMode() throws Exception { 100084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 100184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 100284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson try { 100384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setFixedLengthStreamingMode(-2); 100484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson fail(); 100584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } catch (IllegalArgumentException expected) { 100684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 100784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 100884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 100984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testCanSetNegativeChunkedStreamingMode() throws Exception { 101084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 101184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 101284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setChunkedStreamingMode(-2); 101384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 101484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 101584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testCannotSetFixedLengthStreamingModeAfterConnect() throws Exception { 101684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("A")); 101784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 101884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 101984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 102084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson try { 102184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setFixedLengthStreamingMode(1); 102284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson fail(); 102384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } catch (IllegalStateException expected) { 102484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 102584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 102684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 102784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testCannotSetChunkedStreamingModeAfterConnect() throws Exception { 102884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("A")); 102984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 103084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 103184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 103284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson try { 103384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setChunkedStreamingMode(1); 103484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson fail(); 103584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } catch (IllegalStateException expected) { 103684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 103784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 103884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 103984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testCannotSetFixedLengthStreamingModeAfterChunkedStreamingMode() throws Exception { 104084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 104184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 104284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setChunkedStreamingMode(1); 104384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson try { 104484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setFixedLengthStreamingMode(1); 104584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson fail(); 104684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } catch (IllegalStateException expected) { 104784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 104884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson } 104984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 105084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson public void testCannotSetChunkedStreamingModeAfterFixedLengthStreamingMode() throws Exception { 105184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 105284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 105384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setFixedLengthStreamingMode(1); 105484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson try { 105584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setChunkedStreamingMode(1); 105684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson fail(); 10579531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } catch (IllegalStateException expected) { 10589531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 10599531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 10609531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 10619531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson public void testSecureFixedLengthStreaming() throws Exception { 10629531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson testSecureStreamingPost(StreamingMode.FIXED_LENGTH); 10639531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 10649531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 10659531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson public void testSecureChunkedStreaming() throws Exception { 10669531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson testSecureStreamingPost(StreamingMode.CHUNKED); 10679531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson } 10689531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 10699531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson /** 107084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * Users have reported problems using HTTPS with streaming request bodies. 107184f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson * http://code.google.com/p/android/issues/detail?id=12860 107284f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson */ 107384f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson private void testSecureStreamingPost(StreamingMode streamingMode) throws Exception { 107484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 107584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 107684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.enqueue(new MockResponse().setBody("Success!")); 107784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson server.play(); 107884f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 107984f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 108084f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 1081c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson connection.setDoOutput(true); 108221dddca4064527116af7a1553de502c6d11138daJesse Wilson byte[] requestBody = { 'A', 'B', 'C', 'D' }; 108321dddca4064527116af7a1553de502c6d11138daJesse Wilson if (streamingMode == StreamingMode.FIXED_LENGTH) { 108421dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.setFixedLengthStreamingMode(requestBody.length); 108521dddca4064527116af7a1553de502c6d11138daJesse Wilson } else if (streamingMode == StreamingMode.CHUNKED) { 108621dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.setChunkedStreamingMode(0); 108721dddca4064527116af7a1553de502c6d11138daJesse Wilson } 108821dddca4064527116af7a1553de502c6d11138daJesse Wilson OutputStream outputStream = connection.getOutputStream(); 108921dddca4064527116af7a1553de502c6d11138daJesse Wilson outputStream.write(requestBody); 109021dddca4064527116af7a1553de502c6d11138daJesse Wilson outputStream.close(); 1091953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("Success!", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 109221dddca4064527116af7a1553de502c6d11138daJesse Wilson 109321dddca4064527116af7a1553de502c6d11138daJesse Wilson RecordedRequest request = server.takeRequest(); 109421dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals("POST / HTTP/1.1", request.getRequestLine()); 109521dddca4064527116af7a1553de502c6d11138daJesse Wilson if (streamingMode == StreamingMode.FIXED_LENGTH) { 109621dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals(Collections.<Integer>emptyList(), request.getChunkSizes()); 109721dddca4064527116af7a1553de502c6d11138daJesse Wilson } else if (streamingMode == StreamingMode.CHUNKED) { 109821dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals(Arrays.asList(4), request.getChunkSizes()); 109921dddca4064527116af7a1553de502c6d11138daJesse Wilson } 110021dddca4064527116af7a1553de502c6d11138daJesse Wilson assertEquals(Arrays.toString(requestBody), Arrays.toString(request.getBody())); 110121dddca4064527116af7a1553de502c6d11138daJesse Wilson } 110221dddca4064527116af7a1553de502c6d11138daJesse Wilson 110321dddca4064527116af7a1553de502c6d11138daJesse Wilson enum StreamingMode { 110421dddca4064527116af7a1553de502c6d11138daJesse Wilson FIXED_LENGTH, CHUNKED 110521dddca4064527116af7a1553de502c6d11138daJesse Wilson } 110621dddca4064527116af7a1553de502c6d11138daJesse Wilson 110721dddca4064527116af7a1553de502c6d11138daJesse Wilson public void testAuthenticateWithPost() throws Exception { 110821dddca4064527116af7a1553de502c6d11138daJesse Wilson MockResponse pleaseAuthenticate = new MockResponse() 110921dddca4064527116af7a1553de502c6d11138daJesse Wilson .setResponseCode(401) 111021dddca4064527116af7a1553de502c6d11138daJesse Wilson .addHeader("WWW-Authenticate: Basic realm=\"protected area\"") 111121dddca4064527116af7a1553de502c6d11138daJesse Wilson .setBody("Please authenticate."); 111221dddca4064527116af7a1553de502c6d11138daJesse Wilson // fail auth three times... 111321dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(pleaseAuthenticate); 111421dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(pleaseAuthenticate); 111521dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(pleaseAuthenticate); 111621dddca4064527116af7a1553de502c6d11138daJesse Wilson // ...then succeed the fourth time 111721dddca4064527116af7a1553de502c6d11138daJesse Wilson server.enqueue(new MockResponse().setBody("Successful auth!")); 111821dddca4064527116af7a1553de502c6d11138daJesse Wilson server.play(); 111921dddca4064527116af7a1553de502c6d11138daJesse Wilson 1120953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson Authenticator.setDefault(SIMPLE_AUTHENTICATOR); 112121dddca4064527116af7a1553de502c6d11138daJesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 112221dddca4064527116af7a1553de502c6d11138daJesse Wilson connection.setDoOutput(true); 112321dddca4064527116af7a1553de502c6d11138daJesse Wilson byte[] requestBody = { 'A', 'B', 'C', 'D' }; 112421dddca4064527116af7a1553de502c6d11138daJesse Wilson OutputStream outputStream = connection.getOutputStream(); 112521dddca4064527116af7a1553de502c6d11138daJesse Wilson outputStream.write(requestBody); 1126953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson outputStream.close(); 1127953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1128953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1129953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // no authorization header for the first request... 1130953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson RecordedRequest request = server.takeRequest(); 1131953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertContainsNoneMatching(request.getHeaders(), "Authorization: Basic .*"); 1132953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1133953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // ...but the three requests that follow include an authorization header 1134953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson for (int i = 0; i < 3; i++) { 1135953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson request = server.takeRequest(); 1136953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals("POST / HTTP/1.1", request.getRequestLine()); 1137953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertContains(request.getHeaders(), "Authorization: Basic " + BASE_64_CREDENTIALS); 1138953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertEquals(Arrays.toString(requestBody), Arrays.toString(request.getBody())); 1139953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1140953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1141953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1142953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testAuthenticateWithGet() throws Exception { 1143953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson MockResponse pleaseAuthenticate = new MockResponse() 1144953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setResponseCode(401) 1145953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .addHeader("WWW-Authenticate: Basic realm=\"protected area\"") 1146953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson .setBody("Please authenticate."); 1147953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // fail auth three times... 1148953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(pleaseAuthenticate); 1149953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(pleaseAuthenticate); 1150953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(pleaseAuthenticate); 1151953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson // ...then succeed the fourth time 1152953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.enqueue(new MockResponse().setBody("Successful auth!")); 1153953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson server.play(); 1154953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1155953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson Authenticator.setDefault(SIMPLE_AUTHENTICATOR); 115619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 115719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 115819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 115919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson // no authorization header for the first request... 116019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson RecordedRequest request = server.takeRequest(); 116119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertContainsNoneMatching(request.getHeaders(), "Authorization: Basic .*"); 116219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 116319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson // ...but the three requests that follow requests include an authorization header 116419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson for (int i = 0; i < 3; i++) { 116519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson request = server.takeRequest(); 116619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("GET / HTTP/1.1", request.getRequestLine()); 116719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertContains(request.getHeaders(), "Authorization: Basic " + BASE_64_CREDENTIALS); 116819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 116919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 117019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 117119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testRedirectedWithChunkedEncoding() throws Exception { 117219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson testRedirected(TransferKind.CHUNKED, true); 117319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 117419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 117519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testRedirectedWithContentLengthHeader() throws Exception { 117619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson testRedirected(TransferKind.FIXED_LENGTH, true); 117719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 117819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 117919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson public void testRedirectedWithNoLengthHeaders() throws Exception { 118019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson testRedirected(TransferKind.END_OF_STREAM, false); 118119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson } 118219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 118319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson private void testRedirected(TransferKind transferKind, boolean reuse) throws Exception { 118419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson MockResponse response = new MockResponse() 118519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 118619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson .addHeader("Location: /foo"); 118719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson transferKind.setBody(response, "This page has moved!", 10); 118819c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(response); 118919c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.enqueue(new MockResponse().setBody("This is the new location!")); 119019c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson server.play(); 119119c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 119219c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 119319c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("This is the new location!", 119419c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 119519c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson 119619c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson RecordedRequest first = server.takeRequest(); 119719c77c6a6da8cea7327ccbb741963ac76d3fae53Jesse Wilson assertEquals("GET / HTTP/1.1", first.getRequestLine()); 11982f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson RecordedRequest retry = server.takeRequest(); 11992f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("GET /foo HTTP/1.1", retry.getRequestLine()); 12002f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson if (reuse) { 12012f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson assertEquals("Expected connection reuse", 1, retry.getSequenceNumber()); 12022f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 12032f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson } 12042f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 12052f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson public void testRedirectedOnHttps() throws IOException, InterruptedException { 12062f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 12072f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 12082f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse() 12092f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 12102f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .addHeader("Location: /foo") 12112f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson .setBody("This page has moved!")); 12122f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.enqueue(new MockResponse().setBody("This is the new location!")); 12132f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson server.play(); 12142f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson 12152f16d502415452f808b5f077ad07b941645d14e4Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 1216757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 1217757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("This is the new location!", 1218757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1219757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1220757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson RecordedRequest first = server.takeRequest(); 1221757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("GET / HTTP/1.1", first.getRequestLine()); 1222757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson RecordedRequest retry = server.takeRequest(); 1223757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("GET /foo HTTP/1.1", retry.getRequestLine()); 1224757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("Expected connection reuse", 1, retry.getSequenceNumber()); 1225757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1226ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson 1227ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson public void testNotRedirectedFromHttpsToHttp() throws IOException, InterruptedException { 1228ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 1229757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 1230757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1231ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 1232ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson .addHeader("Location: http://anyhost/foo") 1233ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson .setBody("This page has moved!")); 1234757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.play(); 1235757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1236757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 1237757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 1238757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("This page has moved!", 1239757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1240757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson } 1241757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1242757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testNotRedirectedFromHttpToHttps() throws IOException, InterruptedException { 1243757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1244757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 1245757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Location: https://anyhost/foo") 1246ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson .setBody("This page has moved!")); 1247ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.play(); 1248ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson 1249757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1250757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("This page has moved!", 1251ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1252ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson } 1253ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson 1254757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson public void testRedirectToAnotherOriginServer() throws Exception { 1255757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson MockWebServer server2 = new MockWebServer(); 1256757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server2.enqueue(new MockResponse().setBody("This is the 2nd server!")); 1257757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server2.play(); 1258757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson 1259757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson server.enqueue(new MockResponse() 1260757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 1261757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .addHeader("Location: " + server2.getUrl("/").toString()) 1262757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson .setBody("This page has moved!")); 1263ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.enqueue(new MockResponse().setBody("This is the first server again!")); 1264ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson server.play(); 1265ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson 1266757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 1267757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("This is the 2nd server!", 1268ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1269ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson assertEquals(server2.getUrl("/"), connection.getURL()); 1270ca8ae42fd6a787757897a680108bdcf7b0d37f13Jesse Wilson 1271757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson // make sure the first server was careful to recycle the connection 1272757afaa7afe96791a3cc612c9e3c4597a7321c7eJesse Wilson assertEquals("This is the first server again!", 12730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(server.getUrl("/").openStream(), Integer.MAX_VALUE)); 12740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest first = server.takeRequest(); 12760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertContains(first.getHeaders(), "Host: " + hostName + ":" + server.getPort()); 12770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest second = server2.takeRequest(); 1278953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson assertContains(second.getHeaders(), "Host: " + hostName + ":" + server2.getPort()); 12799531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson RecordedRequest third = server.takeRequest(); 12809531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson assertEquals("Expected connection reuse", 1, third.getSequenceNumber()); 12819531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson 12829531eea15052eccc004b5f853ab4452becf7a8abJesse Wilson server2.shutdown(); 1283953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1284953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson 1285953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson public void testResponse300MultipleChoiceWithPost() throws Exception { 12860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Chrome doesn't follow the redirect, but Firefox and the RI both do 12870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseRedirectedWithPost(HttpURLConnection.HTTP_MULT_CHOICE); 12880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12900c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponse301MovedPermanentlyWithPost() throws Exception { 12910c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_PERM); 12920c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12930c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12940c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponse302MovedTemporarilyWithPost() throws Exception { 12950c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseRedirectedWithPost(HttpURLConnection.HTTP_MOVED_TEMP); 12960c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 12970c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 12980c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponse303SeeOtherWithPost() throws Exception { 12990c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson testResponseRedirectedWithPost(HttpURLConnection.HTTP_SEE_OTHER); 13000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson private void testResponseRedirectedWithPost(int redirectCode) throws Exception { 13030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 13040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(redirectCode) 13050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: /page2") 13060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("This page has moved!")); 13070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Page 2")); 13080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 13090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/page1").openConnection(); 13110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson connection.setDoOutput(true); 13120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson byte[] requestBody = { 'A', 'B', 'C', 'D' }; 13130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson OutputStream outputStream = connection.getOutputStream(); 13140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson outputStream.write(requestBody); 13150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson outputStream.close(); 13160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("Page 2", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 13170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertTrue(connection.getDoOutput()); 13180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest page1 = server.takeRequest(); 13200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("POST /page1 HTTP/1.1", page1.getRequestLine()); 13210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.toString(requestBody), Arrays.toString(page1.getBody())); 13220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest page2 = server.takeRequest(); 13240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("GET /page2 HTTP/1.1", page2.getRequestLine()); 13250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testResponse305UseProxy() throws Exception { 13280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 13290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse() 13300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setResponseCode(HttpURLConnection.HTTP_USE_PROXY) 13310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Location: " + server.getUrl("/")) 13320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("This page has moved!")); 13330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("Proxy Response")); 13340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection connection = (HttpURLConnection) server.getUrl("/foo").openConnection(); 13360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson // Fails on the RI, which gets "Proxy Response" 13370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("This page has moved!", 13380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 13390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest page1 = server.takeRequest(); 13410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("GET /foo HTTP/1.1", page1.getRequestLine()); 13420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(1, server.getRequestCount()); 13430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testHttpsWithCustomTrustManager() throws Exception { 13460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier(); 13470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordingTrustManager trustManager = new RecordingTrustManager(); 13480c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson SSLContext sc = SSLContext.getInstance("TLS"); 13490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson sc.init(null, new TrustManager[] { trustManager }, new java.security.SecureRandom()); 13500c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); 13520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); 13530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson SSLSocketFactory defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); 13540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 13550c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 13560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 13570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 13580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("ABC")); 13590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("DEF")); 13600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("GHI")); 13610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 13620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URL url = server.getUrl("/"); 136484f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("ABC", readAscii(url.openStream(), Integer.MAX_VALUE)); 136584f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("DEF", readAscii(url.openStream(), Integer.MAX_VALUE)); 136684f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson assertEquals("GHI", readAscii(url.openStream(), Integer.MAX_VALUE)); 136784f1fd18b9db6fc6f2bb65694bee99d42f88bb79Jesse Wilson 13680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("verify " + hostName), hostnameVerifier.calls); 13690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(Arrays.asList("checkServerTrusted [" 13700c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson + "CN=" + hostName + " 1, " 13710c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson + "CN=Test Intermediate Certificate Authority 1, " 13720c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson + "CN=Test Root Certificate Authority 1" 13730c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson + "] RSA"), 13740c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson trustManager.calls); 13750c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } finally { 13760c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection.setDefaultHostnameVerifier(defaultHostnameVerifier); 13770c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpsURLConnection.setDefaultSSLSocketFactory(defaultSSLSocketFactory); 13780c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13790c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 13800c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 13810c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectTimeouts() throws IOException { 13820c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson StuckServer ss = new StuckServer(); 13830c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson int serverPort = ss.getLocalPort(); 13840c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection urlConnection = new URL("http://localhost:" + serverPort).openConnection(); 13850c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson int timeout = 1000; 13860c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.setConnectTimeout(timeout); 13870c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson long start = System.currentTimeMillis(); 13880c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 13890c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.getInputStream(); 1390953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson fail(); 1391c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } catch (SocketTimeoutException expected) { 1392c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson long actual = System.currentTimeMillis() - start; 1393c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson assertTrue(Math.abs(timeout - actual) < 500); 1394c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson } finally { 1395c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson ss.close(); 1396953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1397953df613522e12a418cb7cb73248594d6c9f53d4Jesse Wilson } 1398c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson 1399c9e12f729cb962eb60754e4500312421c46e71ddJesse Wilson public void testReadTimeouts() throws IOException { 14000c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson /* 14010c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * This relies on the fact that MockWebServer doesn't close the 14020c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * connection after a response has been sent. This causes the client to 14030c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson * try to read more bytes than are sent, which results in a timeout. 14040c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson */ 14050c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson MockResponse timeout = new MockResponse() 14060c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .setBody("ABC") 14070c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .clearHeaders() 14080c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson .addHeader("Content-Length: 4"); 14090c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(timeout); 14100c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().setBody("unused")); // to keep the server alive 14110c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 14120c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14130c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson URLConnection urlConnection = server.getUrl("/").openConnection(); 14140c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.setReadTimeout(1000); 14150c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson InputStream in = urlConnection.getInputStream(); 14160c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals('A', in.read()); 14170c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals('B', in.read()); 14180c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals('C', in.read()); 14190c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson try { 14200c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson in.read(); // if Content-Length was accurate, this would return -1 immediately 14210c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson fail(); 14220c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } catch (SocketTimeoutException expected) { 14230c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 14240c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 14250c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14260c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testSetChunkedEncodingAsRequestProperty() throws IOException, InterruptedException { 14270c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse()); 14280c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 14290c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14300c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection urlConnection = (HttpURLConnection) server.getUrl("/").openConnection(); 14310c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.setRequestProperty("Transfer-encoding", "chunked"); 14320c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.setDoOutput(true); 14330c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson urlConnection.getOutputStream().write("ABC".getBytes("UTF-8")); 14340c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, urlConnection.getResponseCode()); 14350c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14360c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson RecordedRequest request = server.takeRequest(); 14370c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("ABC", new String(request.getBody(), "UTF-8")); 14380c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson } 14390c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14400c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectionCloseInRequest() throws IOException, InterruptedException { 14410c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse()); // server doesn't honor the connection: close header! 14420c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse()); 14430c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 14440c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14450c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection a = (HttpURLConnection) server.getUrl("/").openConnection(); 14460c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson a.setRequestProperty("Connection", "close"); 14470c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, a.getResponseCode()); 1448433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson 14490c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection b = (HttpURLConnection) server.getUrl("/").openConnection(); 1450433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson assertEquals(200, b.getResponseCode()); 14510c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14520c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 14530c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("When connection: close is used, each request should get its own connection", 14540c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 0, server.takeRequest().getSequenceNumber()); 1455433e3fac172d0c4449051b0c61c0c63b298a0903Jesse Wilson } 14560c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14570c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson public void testConnectionCloseInResponse() throws IOException, InterruptedException { 14580c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse().addHeader("Connection: close")); 14590c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.enqueue(new MockResponse()); 14600c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson server.play(); 14610c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14620c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection a = (HttpURLConnection) server.getUrl("/").openConnection(); 14630c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, a.getResponseCode()); 14640c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14650c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson HttpURLConnection b = (HttpURLConnection) server.getUrl("/").openConnection(); 14660c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(200, b.getResponseCode()); 14670c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson 14680c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 14690c59055dd24e1659f85d9ff7e2148883f663bd62Jesse Wilson assertEquals("When connection: close is used, each request should get its own connection", 1470 0, server.takeRequest().getSequenceNumber()); 1471 } 1472 1473 public void testConnectionCloseWithRedirect() throws IOException, InterruptedException { 1474 MockResponse response = new MockResponse() 1475 .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 1476 .addHeader("Location: /foo") 1477 .addHeader("Connection: close"); 1478 server.enqueue(response); 1479 server.enqueue(new MockResponse().setBody("This is the new location!")); 1480 server.play(); 1481 1482 URLConnection connection = server.getUrl("/").openConnection(); 1483 assertEquals("This is the new location!", 1484 readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1485 1486 assertEquals(0, server.takeRequest().getSequenceNumber()); 1487 assertEquals("When connection: close is used, each request should get its own connection", 1488 0, server.takeRequest().getSequenceNumber()); 1489 } 1490 1491 public void testResponseCodeDisagreesWithHeaders() throws IOException, InterruptedException { 1492 server.enqueue(new MockResponse() 1493 .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT) 1494 .setBody("This body is not allowed!")); 1495 server.play(); 1496 1497 URLConnection connection = server.getUrl("/").openConnection(); 1498 assertEquals("This body is not allowed!", 1499 readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1500 } 1501 1502 public void testSingleByteReadIsSigned() throws IOException { 1503 server.enqueue(new MockResponse().setBody(new byte[] { -2, -1 })); 1504 server.play(); 1505 1506 URLConnection connection = server.getUrl("/").openConnection(); 1507 InputStream in = connection.getInputStream(); 1508 assertEquals(254, in.read()); 1509 assertEquals(255, in.read()); 1510 assertEquals(-1, in.read()); 1511 } 1512 1513 public void testFlushAfterStreamTransmittedWithChunkedEncoding() throws IOException { 1514 testFlushAfterStreamTransmitted(TransferKind.CHUNKED); 1515 } 1516 1517 public void testFlushAfterStreamTransmittedWithFixedLength() throws IOException { 1518 testFlushAfterStreamTransmitted(TransferKind.FIXED_LENGTH); 1519 } 1520 1521 public void testFlushAfterStreamTransmittedWithNoLengthHeaders() throws IOException { 1522 testFlushAfterStreamTransmitted(TransferKind.END_OF_STREAM); 1523 } 1524 1525 /** 1526 * We explicitly permit apps to close the upload stream even after it has 1527 * been transmitted. We also permit flush so that buffered streams can 1528 * do a no-op flush when they are closed. http://b/3038470 1529 */ 1530 private void testFlushAfterStreamTransmitted(TransferKind transferKind) throws IOException { 1531 server.enqueue(new MockResponse().setBody("abc")); 1532 server.play(); 1533 1534 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1535 connection.setDoOutput(true); 1536 byte[] upload = "def".getBytes("UTF-8"); 1537 1538 if (transferKind == TransferKind.CHUNKED) { 1539 connection.setChunkedStreamingMode(0); 1540 } else if (transferKind == TransferKind.FIXED_LENGTH) { 1541 connection.setFixedLengthStreamingMode(upload.length); 1542 } 1543 1544 OutputStream out = connection.getOutputStream(); 1545 out.write(upload); 1546 assertEquals("abc", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1547 1548 out.flush(); // dubious but permitted 1549 try { 1550 out.write("ghi".getBytes("UTF-8")); 1551 fail(); 1552 } catch (IOException expected) { 1553 } 1554 } 1555 1556 public void testGetHeadersThrows() throws IOException { 1557 server.enqueue(new MockResponse().setSocketPolicy(DISCONNECT_AT_START)); 1558 server.play(); 1559 1560 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1561 try { 1562 connection.getInputStream(); 1563 fail(); 1564 } catch (IOException expected) { 1565 } 1566 1567 try { 1568 connection.getInputStream(); 1569 fail(); 1570 } catch (IOException expected) { 1571 } 1572 } 1573 1574 public void testGetKeepAlive() throws Exception { 1575 MockWebServer server = new MockWebServer(); 1576 server.enqueue(new MockResponse().setBody("ABC")); 1577 server.play(); 1578 1579 // The request should work once and then fail 1580 URLConnection connection = server.getUrl("").openConnection(); 1581 InputStream input = connection.getInputStream(); 1582 assertEquals("ABC", readAscii(input, Integer.MAX_VALUE)); 1583 input.close(); 1584 try { 1585 server.getUrl("").openConnection().getInputStream(); 1586 fail(); 1587 } catch (ConnectException expected) { 1588 } 1589 } 1590 1591 /** 1592 * This test goes through the exhaustive set of interesting ASCII characters 1593 * because most of those characters are interesting in some way according to 1594 * RFC 2396 and RFC 2732. http://b/1158780 1595 */ 1596 public void testLenientUrlToUri() throws Exception { 1597 // alphanum 1598 testUrlToUriMapping("abzABZ09", "abzABZ09", "abzABZ09", "abzABZ09", "abzABZ09"); 1599 1600 // control characters 1601 testUrlToUriMapping("\u0001", "%01", "%01", "%01", "%01"); 1602 testUrlToUriMapping("\u001f", "%1F", "%1F", "%1F", "%1F"); 1603 1604 // ascii characters 1605 testUrlToUriMapping("%20", "%20", "%20", "%20", "%20"); 1606 testUrlToUriMapping("%20", "%20", "%20", "%20", "%20"); 1607 testUrlToUriMapping(" ", "%20", "%20", "%20", "%20"); 1608 testUrlToUriMapping("!", "!", "!", "!", "!"); 1609 testUrlToUriMapping("\"", "%22", "%22", "%22", "%22"); 1610 testUrlToUriMapping("#", null, null, null, "%23"); 1611 testUrlToUriMapping("$", "$", "$", "$", "$"); 1612 testUrlToUriMapping("&", "&", "&", "&", "&"); 1613 testUrlToUriMapping("'", "'", "'", "'", "'"); 1614 testUrlToUriMapping("(", "(", "(", "(", "("); 1615 testUrlToUriMapping(")", ")", ")", ")", ")"); 1616 testUrlToUriMapping("*", "*", "*", "*", "*"); 1617 testUrlToUriMapping("+", "+", "+", "+", "+"); 1618 testUrlToUriMapping(",", ",", ",", ",", ","); 1619 testUrlToUriMapping("-", "-", "-", "-", "-"); 1620 testUrlToUriMapping(".", ".", ".", ".", "."); 1621 testUrlToUriMapping("/", null, "/", "/", "/"); 1622 testUrlToUriMapping(":", null, ":", ":", ":"); 1623 testUrlToUriMapping(";", ";", ";", ";", ";"); 1624 testUrlToUriMapping("<", "%3C", "%3C", "%3C", "%3C"); 1625 testUrlToUriMapping("=", "=", "=", "=", "="); 1626 testUrlToUriMapping(">", "%3E", "%3E", "%3E", "%3E"); 1627 testUrlToUriMapping("?", null, null, "?", "?"); 1628 testUrlToUriMapping("@", "@", "@", "@", "@"); 1629 testUrlToUriMapping("[", null, "%5B", null, "%5B"); 1630 testUrlToUriMapping("\\", "%5C", "%5C", "%5C", "%5C"); 1631 testUrlToUriMapping("]", null, "%5D", null, "%5D"); 1632 testUrlToUriMapping("^", "%5E", "%5E", "%5E", "%5E"); 1633 testUrlToUriMapping("_", "_", "_", "_", "_"); 1634 testUrlToUriMapping("`", "%60", "%60", "%60", "%60"); 1635 testUrlToUriMapping("{", "%7B", "%7B", "%7B", "%7B"); 1636 testUrlToUriMapping("|", "%7C", "%7C", "%7C", "%7C"); 1637 testUrlToUriMapping("}", "%7D", "%7D", "%7D", "%7D"); 1638 testUrlToUriMapping("~", "~", "~", "~", "~"); 1639 testUrlToUriMapping("~", "~", "~", "~", "~"); 1640 testUrlToUriMapping("\u007f", "%7F", "%7F", "%7F", "%7F"); 1641 1642 // beyond ascii 1643 testUrlToUriMapping("\u0080", "%C2%80", "%C2%80", "%C2%80", "%C2%80"); 1644 testUrlToUriMapping("\u20ac", "\u20ac", "\u20ac", "\u20ac", "\u20ac"); 1645 testUrlToUriMapping("\ud842\udf9f", 1646 "\ud842\udf9f", "\ud842\udf9f", "\ud842\udf9f", "\ud842\udf9f"); 1647 } 1648 1649 public void testLenientUrlToUriNul() throws Exception { 1650 testUrlToUriMapping("\u0000", "%00", "%00", "%00", "%00"); // RI fails this 1651 } 1652 1653 private void testUrlToUriMapping(String string, String asAuthority, String asFile, 1654 String asQuery, String asFragment) throws Exception { 1655 if (asAuthority != null) { 1656 assertEquals("http://host" + asAuthority + ".tld/", 1657 backdoorUrlToUri(new URL("http://host" + string + ".tld/")).toString()); 1658 } 1659 if (asFile != null) { 1660 assertEquals("http://host.tld/file" + asFile + "/", 1661 backdoorUrlToUri(new URL("http://host.tld/file" + string + "/")).toString()); 1662 } 1663 if (asQuery != null) { 1664 assertEquals("http://host.tld/file?q" + asQuery + "=x", 1665 backdoorUrlToUri(new URL("http://host.tld/file?q" + string + "=x")).toString()); 1666 } 1667 assertEquals("http://host.tld/file#" + asFragment + "-x", 1668 backdoorUrlToUri(new URL("http://host.tld/file#" + asFragment + "-x")).toString()); 1669 } 1670 1671 /** 1672 * Exercises HttpURLConnection to convert URL to a URI. Unlike URL#toURI, 1673 * HttpURLConnection recovers from URLs with unescaped but unsupported URI 1674 * characters like '{' and '|' by escaping these characters. 1675 */ 1676 private URI backdoorUrlToUri(URL url) throws Exception { 1677 final AtomicReference<URI> uriReference = new AtomicReference<URI>(); 1678 1679 ResponseCache.setDefault(new ResponseCache() { 1680 @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 1681 return null; 1682 } 1683 @Override public CacheResponse get(URI uri, String requestMethod, 1684 Map<String, List<String>> requestHeaders) throws IOException { 1685 uriReference.set(uri); 1686 throw new UnsupportedOperationException(); 1687 } 1688 }); 1689 1690 try { 1691 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 1692 connection.getResponseCode(); 1693 } catch (Exception expected) { 1694 } 1695 1696 return uriReference.get(); 1697 } 1698 1699 /** 1700 * Don't explode if the cache returns a null body. http://b/3373699 1701 */ 1702 public void testResponseCacheReturnsNullOutputStream() throws Exception { 1703 final AtomicBoolean aborted = new AtomicBoolean(); 1704 ResponseCache.setDefault(new ResponseCache() { 1705 @Override public CacheResponse get(URI uri, String requestMethod, 1706 Map<String, List<String>> requestHeaders) throws IOException { 1707 return null; 1708 } 1709 @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException { 1710 return new CacheRequest() { 1711 @Override public void abort() { 1712 aborted.set(true); 1713 } 1714 @Override public OutputStream getBody() throws IOException { 1715 return null; 1716 } 1717 }; 1718 } 1719 }); 1720 1721 server.enqueue(new MockResponse().setBody("abcdef")); 1722 server.play(); 1723 1724 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1725 InputStream in = connection.getInputStream(); 1726 assertEquals("abc", readAscii(in, 3)); 1727 in.close(); 1728 assertFalse(aborted.get()); // The best behavior is ambiguous, but RI 6 doesn't abort here 1729 } 1730 1731 1732 /** 1733 * http://code.google.com/p/android/issues/detail?id=14562 1734 */ 1735 public void testReadAfterLastByte() throws Exception { 1736 server.enqueue(new MockResponse() 1737 .setBody("ABC") 1738 .clearHeaders() 1739 .addHeader("Connection: close") 1740 .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END)); 1741 server.play(); 1742 1743 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1744 InputStream in = connection.getInputStream(); 1745 assertEquals("ABC", readAscii(in, 3)); 1746 assertEquals(-1, in.read()); 1747 assertEquals(-1, in.read()); // throws IOException in Gingerbread 1748 } 1749 1750 public void testGetContent() throws Exception { 1751 server.enqueue(new MockResponse().setBody("A")); 1752 server.play(); 1753 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1754 InputStream in = (InputStream) connection.getContent(); 1755 assertEquals("A", readAscii(in, Integer.MAX_VALUE)); 1756 } 1757 1758 public void testGetContentOfType() throws Exception { 1759 server.enqueue(new MockResponse().setBody("A")); 1760 server.play(); 1761 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1762 try { 1763 connection.getContent(null); 1764 fail(); 1765 } catch (NullPointerException expected) { 1766 } 1767 try { 1768 connection.getContent(new Class[] { null }); 1769 fail(); 1770 } catch (NullPointerException expected) { 1771 } 1772 assertNull(connection.getContent(new Class[] { getClass() })); 1773 connection.disconnect(); 1774 } 1775 1776 public void testGetOutputStreamOnGetFails() throws Exception { 1777 server.enqueue(new MockResponse()); 1778 server.play(); 1779 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1780 try { 1781 connection.getOutputStream(); 1782 fail(); 1783 } catch (ProtocolException expected) { 1784 } 1785 } 1786 1787 public void testGetOutputAfterGetInputStreamFails() throws Exception { 1788 server.enqueue(new MockResponse()); 1789 server.play(); 1790 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1791 connection.setDoOutput(true); 1792 try { 1793 connection.getInputStream(); 1794 connection.getOutputStream(); 1795 fail(); 1796 } catch (ProtocolException expected) { 1797 } 1798 } 1799 1800 public void testSetDoOutputOrDoInputAfterConnectFails() throws Exception { 1801 server.enqueue(new MockResponse()); 1802 server.play(); 1803 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1804 connection.connect(); 1805 try { 1806 connection.setDoOutput(true); 1807 fail(); 1808 } catch (IllegalStateException expected) { 1809 } 1810 try { 1811 connection.setDoInput(true); 1812 fail(); 1813 } catch (IllegalStateException expected) { 1814 } 1815 connection.disconnect(); 1816 } 1817 1818 public void testClientSendsContentLength() throws Exception { 1819 server.enqueue(new MockResponse().setBody("A")); 1820 server.play(); 1821 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1822 connection.setDoOutput(true); 1823 OutputStream out = connection.getOutputStream(); 1824 out.write(new byte[] { 'A', 'B', 'C' }); 1825 out.close(); 1826 assertEquals("A", readAscii(connection.getInputStream(), Integer.MAX_VALUE)); 1827 RecordedRequest request = server.takeRequest(); 1828 assertContains(request.getHeaders(), "Content-Length: 3"); 1829 } 1830 1831 public void testGetContentLengthConnects() throws Exception { 1832 server.enqueue(new MockResponse().setBody("ABC")); 1833 server.play(); 1834 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1835 assertEquals(3, connection.getContentLength()); 1836 connection.disconnect(); 1837 } 1838 1839 public void testGetContentTypeConnects() throws Exception { 1840 server.enqueue(new MockResponse() 1841 .addHeader("Content-Type: text/plain") 1842 .setBody("ABC")); 1843 server.play(); 1844 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1845 assertEquals("text/plain", connection.getContentType()); 1846 connection.disconnect(); 1847 } 1848 1849 public void testGetContentEncodingConnects() throws Exception { 1850 server.enqueue(new MockResponse() 1851 .addHeader("Content-Encoding: identity") 1852 .setBody("ABC")); 1853 server.play(); 1854 HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection(); 1855 assertEquals("identity", connection.getContentEncoding()); 1856 connection.disconnect(); 1857 } 1858 1859 // http://b/4361656 1860 public void testUrlContainsQueryButNoPath() throws Exception { 1861 server.enqueue(new MockResponse().setBody("A")); 1862 server.play(); 1863 URL url = new URL("http", server.getHostName(), server.getPort(), "?query"); 1864 assertEquals("A", readAscii(url.openConnection().getInputStream(), Integer.MAX_VALUE)); 1865 RecordedRequest request = server.takeRequest(); 1866 assertEquals("GET /?query HTTP/1.1", request.getRequestLine()); 1867 } 1868 1869 // http://code.google.com/p/android/issues/detail?id=20442 1870 public void testInputStreamAvailableWithChunkedEncoding() throws Exception { 1871 testInputStreamAvailable(TransferKind.CHUNKED); 1872 } 1873 1874 public void testInputStreamAvailableWithContentLengthHeader() throws Exception { 1875 testInputStreamAvailable(TransferKind.FIXED_LENGTH); 1876 } 1877 1878 public void testInputStreamAvailableWithNoLengthHeaders() throws Exception { 1879 testInputStreamAvailable(TransferKind.END_OF_STREAM); 1880 } 1881 1882 private void testInputStreamAvailable(TransferKind transferKind) throws IOException { 1883 String body = "ABCDEFGH"; 1884 MockResponse response = new MockResponse(); 1885 transferKind.setBody(response, body, 4); 1886 server.enqueue(response); 1887 server.play(); 1888 URLConnection connection = server.getUrl("/").openConnection(); 1889 InputStream in = connection.getInputStream(); 1890 for (int i = 0; i < body.length(); i++) { 1891 assertTrue(in.available() >= 0); 1892 assertEquals(body.charAt(i), in.read()); 1893 } 1894 assertEquals(0, in.available()); 1895 assertEquals(-1, in.read()); 1896 } 1897 1898 public void testInspectSslBeforeConnect() throws Exception { 1899 TestSSLContext testSSLContext = TestSSLContext.create(); 1900 server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 1901 server.enqueue(new MockResponse()); 1902 server.play(); 1903 1904 HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 1905 connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 1906 assertNotNull(connection.getHostnameVerifier()); 1907 try { 1908 connection.getLocalCertificates(); 1909 fail(); 1910 } catch (IllegalStateException expected) { 1911 } 1912 try { 1913 connection.getServerCertificates(); 1914 fail(); 1915 } catch (IllegalStateException expected) { 1916 } 1917 try { 1918 connection.getCipherSuite(); 1919 fail(); 1920 } catch (IllegalStateException expected) { 1921 } 1922 try { 1923 connection.getPeerPrincipal(); 1924 fail(); 1925 } catch (IllegalStateException expected) { 1926 } 1927 } 1928 1929 /** 1930 * Test that we can inspect the SSL session after connect(). 1931 * http://code.google.com/p/android/issues/detail?id=24431 1932 */ 1933 public void testInspectSslAfterConnect() throws Exception { 1934 TestSSLContext testSSLContext = TestSSLContext.create(); 1935 server.useHttps(testSSLContext.serverContext.getSocketFactory(), false); 1936 server.enqueue(new MockResponse()); 1937 server.play(); 1938 1939 HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection(); 1940 connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory()); 1941 connection.connect(); 1942 assertNotNull(connection.getHostnameVerifier()); 1943 assertNull(connection.getLocalCertificates()); 1944 assertNotNull(connection.getServerCertificates()); 1945 assertNotNull(connection.getCipherSuite()); 1946 assertNotNull(connection.getPeerPrincipal()); 1947 } 1948 1949 /** 1950 * Returns a gzipped copy of {@code bytes}. 1951 */ 1952 public byte[] gzip(byte[] bytes) throws IOException { 1953 ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 1954 OutputStream gzippedOut = new GZIPOutputStream(bytesOut); 1955 gzippedOut.write(bytes); 1956 gzippedOut.close(); 1957 return bytesOut.toByteArray(); 1958 } 1959 1960 /** 1961 * Reads at most {@code limit} characters from {@code in} and asserts that 1962 * content equals {@code expected}. 1963 */ 1964 private void assertContent(String expected, URLConnection connection, int limit) 1965 throws IOException { 1966 connection.connect(); 1967 assertEquals(expected, readAscii(connection.getInputStream(), limit)); 1968 ((HttpURLConnection) connection).disconnect(); 1969 } 1970 1971 private void assertContent(String expected, URLConnection connection) throws IOException { 1972 assertContent(expected, connection, Integer.MAX_VALUE); 1973 } 1974 1975 private void assertContains(List<String> headers, String header) { 1976 assertTrue(headers.toString(), headers.contains(header)); 1977 } 1978 1979 private void assertContainsNoneMatching(List<String> headers, String pattern) { 1980 for (String header : headers) { 1981 if (header.matches(pattern)) { 1982 fail("Header " + header + " matches " + pattern); 1983 } 1984 } 1985 } 1986 1987 private Set<String> newSet(String... elements) { 1988 return new HashSet<String>(Arrays.asList(elements)); 1989 } 1990 1991 enum TransferKind { 1992 CHUNKED() { 1993 @Override void setBody(MockResponse response, byte[] content, int chunkSize) 1994 throws IOException { 1995 response.setChunkedBody(content, chunkSize); 1996 } 1997 }, 1998 FIXED_LENGTH() { 1999 @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 2000 response.setBody(content); 2001 } 2002 }, 2003 END_OF_STREAM() { 2004 @Override void setBody(MockResponse response, byte[] content, int chunkSize) { 2005 response.setBody(content); 2006 response.setSocketPolicy(DISCONNECT_AT_END); 2007 for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 2008 if (h.next().startsWith("Content-Length:")) { 2009 h.remove(); 2010 break; 2011 } 2012 } 2013 } 2014 }; 2015 2016 abstract void setBody(MockResponse response, byte[] content, int chunkSize) 2017 throws IOException; 2018 2019 void setBody(MockResponse response, String content, int chunkSize) throws IOException { 2020 setBody(response, content.getBytes("UTF-8"), chunkSize); 2021 } 2022 } 2023 2024 enum ProxyConfig { 2025 NO_PROXY() { 2026 @Override public HttpURLConnection connect(MockWebServer server, URL url) 2027 throws IOException { 2028 return (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); 2029 } 2030 }, 2031 2032 CREATE_ARG() { 2033 @Override public HttpURLConnection connect(MockWebServer server, URL url) 2034 throws IOException { 2035 return (HttpURLConnection) url.openConnection(server.toProxyAddress()); 2036 } 2037 }, 2038 2039 PROXY_SYSTEM_PROPERTY() { 2040 @Override public HttpURLConnection connect(MockWebServer server, URL url) 2041 throws IOException { 2042 System.setProperty("proxyHost", "localhost"); 2043 System.setProperty("proxyPort", Integer.toString(server.getPort())); 2044 return (HttpURLConnection) url.openConnection(); 2045 } 2046 }, 2047 2048 HTTP_PROXY_SYSTEM_PROPERTY() { 2049 @Override public HttpURLConnection connect(MockWebServer server, URL url) 2050 throws IOException { 2051 System.setProperty("http.proxyHost", "localhost"); 2052 System.setProperty("http.proxyPort", Integer.toString(server.getPort())); 2053 return (HttpURLConnection) url.openConnection(); 2054 } 2055 }, 2056 2057 HTTPS_PROXY_SYSTEM_PROPERTY() { 2058 @Override public HttpURLConnection connect(MockWebServer server, URL url) 2059 throws IOException { 2060 System.setProperty("https.proxyHost", "localhost"); 2061 System.setProperty("https.proxyPort", Integer.toString(server.getPort())); 2062 return (HttpURLConnection) url.openConnection(); 2063 } 2064 }; 2065 2066 public abstract HttpURLConnection connect(MockWebServer server, URL url) throws IOException; 2067 } 2068 2069 private static class RecordingTrustManager implements X509TrustManager { 2070 private final List<String> calls = new ArrayList<String>(); 2071 2072 public X509Certificate[] getAcceptedIssuers() { 2073 calls.add("getAcceptedIssuers"); 2074 return new X509Certificate[] {}; 2075 } 2076 2077 public void checkClientTrusted(X509Certificate[] chain, String authType) 2078 throws CertificateException { 2079 calls.add("checkClientTrusted " + certificatesToString(chain) + " " + authType); 2080 } 2081 2082 public void checkServerTrusted(X509Certificate[] chain, String authType) 2083 throws CertificateException { 2084 calls.add("checkServerTrusted " + certificatesToString(chain) + " " + authType); 2085 } 2086 2087 private String certificatesToString(X509Certificate[] certificates) { 2088 List<String> result = new ArrayList<String>(); 2089 for (X509Certificate certificate : certificates) { 2090 result.add(certificate.getSubjectDN() + " " + certificate.getSerialNumber()); 2091 } 2092 return result.toString(); 2093 } 2094 } 2095 2096 private static class RecordingHostnameVerifier implements HostnameVerifier { 2097 private final List<String> calls = new ArrayList<String>(); 2098 2099 public boolean verify(String hostname, SSLSession session) { 2100 calls.add("verify " + hostname); 2101 return true; 2102 } 2103 } 2104} 2105