URLConnectionTest.java revision 6906b0c12dcf3216883d0373973a252812a20d32
1e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes/* 2e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * Copyright (C) 2009 The Android Open Source Project 3f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 4e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License"); 5e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * you may not use this file except in compliance with the License. 6e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * You may obtain a copy of the License at 7f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 8e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 9f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 10e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * Unless required by applicable law or agreed to in writing, software 11e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 12e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * See the License for the specific language governing permissions and 14e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes * limitations under the License. 15e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes */ 16e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes 17e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughespackage java.net; 18e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes 1951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilsonimport java.io.BufferedReader; 20c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilsonimport java.io.ByteArrayOutputStream; 216247987eb505a482a67f5f19678260d9e7240a5fElliott Hughesimport java.io.IOException; 2251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilsonimport java.io.InputStream; 23e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughesimport java.io.InputStreamReader; 2402f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughesimport java.io.OutputStream; 2551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilsonimport java.util.ArrayList; 2602f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughesimport java.util.Arrays; 2751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilsonimport java.util.Collections; 2851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilsonimport java.util.Iterator; 296247987eb505a482a67f5f19678260d9e7240a5fElliott Hughesimport java.util.List; 3051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilsonimport java.util.Set; 3160476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilsonimport javax.net.ssl.HostnameVerifier; 3260476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilsonimport javax.net.ssl.HttpsURLConnection; 3360476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilsonimport javax.net.ssl.SSLSession; 3460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilsonimport javax.net.ssl.TestSSLContext; 3551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilsonimport tests.http.DefaultResponseCache; 3660476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilsonimport tests.http.MockResponse; 3760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilsonimport tests.http.MockWebServer; 3860476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilsonimport tests.http.RecordedRequest; 39e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes 40e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughespublic class URLConnectionTest extends junit.framework.TestCase { 41b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson 4251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private MockWebServer server = new MockWebServer(); 4351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 4451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson @Override protected void tearDown() throws Exception { 4551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson ResponseCache.setDefault(null); 4651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.shutdown(); 4751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 4851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 49e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes // Check that if we don't read to the end of a response, the next request on the 50e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes // recycled connection doesn't get the unread tail of the first request's response. 51e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes // http://code.google.com/p/android/issues/detail?id=2939 52e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes public void test_2939() throws Exception { 53b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson MockResponse response = new MockResponse().setChunkedBody("ABCDE\nFGHIJ\nKLMNO\nPQR", 8); 54b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson 55b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.enqueue(response); 56b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.enqueue(response); 57b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.play(); 58b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson 59c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDE", server.getUrl("/").openConnection(), 5); 60c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDE", server.getUrl("/").openConnection(), 5); 618baf143a7c8921d07b54adbc66ac1e5b42de5fe6Jesse Wilson } 628baf143a7c8921d07b54adbc66ac1e5b42de5fe6Jesse Wilson 638baf143a7c8921d07b54adbc66ac1e5b42de5fe6Jesse Wilson public void testConnectionsArePooled() throws Exception { 64b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson MockResponse response = new MockResponse().setBody("ABCDEFGHIJKLMNOPQR"); 65b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson 66b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.enqueue(response); 67b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.enqueue(response); 68b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.enqueue(response); 69b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.play(); 70b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson 71c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/").openConnection()); 72c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 73c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/").openConnection()); 74c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 75c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/").openConnection()); 76c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertEquals(2, server.takeRequest().getSequenceNumber()); 77c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson } 78c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 79c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson public void testChunkedConnectionsArePooled() throws Exception { 80c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson MockResponse response = new MockResponse().setChunkedBody("ABCDEFGHIJKLMNOPQR", 5); 81c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 82c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.enqueue(response); 83c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.enqueue(response); 84c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.enqueue(response); 85c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.play(); 86c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 87c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/").openConnection()); 88b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson assertEquals(0, server.takeRequest().getSequenceNumber()); 89c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/").openConnection()); 90b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson assertEquals(1, server.takeRequest().getSequenceNumber()); 91c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("ABCDEFGHIJKLMNOPQR", server.getUrl("/").openConnection()); 92b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson assertEquals(2, server.takeRequest().getSequenceNumber()); 93e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes } 9402f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 95b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson enum WriteKind { BYTE_BY_BYTE, SMALL_BUFFERS, LARGE_BUFFERS } 9602f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 9702f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes public void test_chunkedUpload_byteByByte() throws Exception { 9851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson doUpload(TransferKind.CHUNKED, WriteKind.BYTE_BY_BYTE); 9902f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 10002f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 10102f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes public void test_chunkedUpload_smallBuffers() throws Exception { 10251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson doUpload(TransferKind.CHUNKED, WriteKind.SMALL_BUFFERS); 10302f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 10402f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 10502f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes public void test_chunkedUpload_largeBuffers() throws Exception { 10651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson doUpload(TransferKind.CHUNKED, WriteKind.LARGE_BUFFERS); 10702f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 10802f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 10902f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes public void test_fixedLengthUpload_byteByByte() throws Exception { 11051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson doUpload(TransferKind.FIXED_LENGTH, WriteKind.BYTE_BY_BYTE); 11102f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 11202f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 11302f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes public void test_fixedLengthUpload_smallBuffers() throws Exception { 11451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson doUpload(TransferKind.FIXED_LENGTH, WriteKind.SMALL_BUFFERS); 11502f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 11602f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 11702f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes public void test_fixedLengthUpload_largeBuffers() throws Exception { 11851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson doUpload(TransferKind.FIXED_LENGTH, WriteKind.LARGE_BUFFERS); 11902f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 12002f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes 12151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private void doUpload(TransferKind uploadKind, WriteKind writeKind) throws Exception { 12202f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes int n = 512*1024; 123b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.setBodyLimit(0); 124b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.enqueue(new MockResponse()); 125b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.play(); 126b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson 127b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson HttpURLConnection conn = (HttpURLConnection) server.getUrl("/").openConnection(); 12802f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes conn.setDoOutput(true); 12902f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes conn.setRequestMethod("POST"); 13051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson if (uploadKind == TransferKind.CHUNKED) { 13102f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes conn.setChunkedStreamingMode(-1); 13202f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } else { 13302f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes conn.setFixedLengthStreamingMode(n); 13402f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 13502f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes OutputStream out = conn.getOutputStream(); 13602f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes if (writeKind == WriteKind.BYTE_BY_BYTE) { 13702f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes for (int i = 0; i < n; ++i) { 13802f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes out.write('x'); 13902f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 14002f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } else { 14102f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes byte[] buf = new byte[writeKind == WriteKind.SMALL_BUFFERS ? 256 : 64*1024]; 14202f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes Arrays.fill(buf, (byte) 'x'); 14302f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes for (int i = 0; i < n; i += buf.length) { 14402f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes out.write(buf, 0, Math.min(buf.length, n - i)); 14502f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 14602f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 14702f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes out.close(); 1484cb7f05dc68abb23ae54a5891c369062185f2210Elliott Hughes assertEquals(200, conn.getResponseCode()); 149b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson RecordedRequest request = server.takeRequest(); 150b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson assertEquals(n, request.getBodySize()); 15151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson if (uploadKind == TransferKind.CHUNKED) { 152b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson assertTrue(request.getChunkSizes().size() > 0); 153b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson } else { 154b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson assertTrue(request.getChunkSizes().isEmpty()); 155b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson } 15602f0cb2eb84a112fcf644d7d1fd0b5f94ea2f03bElliott Hughes } 1576247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes 15851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson /** 15951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * Test that response caching is consistent with the RI and the spec. 16051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 16151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson */ 1626247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes public void test_responseCaching() throws Exception { 1636247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes // Test each documented HTTP/1.1 code, plus the first unused value in each range. 1646247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 1656247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes 1666247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes // We can't test 100 because it's not really a response. 1676247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes // assertCached(false, 100); 1686247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 101); 1696247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 102); 1706247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(true, 200); 1716247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 201); 1726247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 202); 1736247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(true, 203); 1746247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 204); 1756247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 205); 1766247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(true, 206); 1776247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 207); 17851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson // (See test_responseCaching_300.) 1796247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(true, 301); 1806247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes for (int i = 302; i <= 308; ++i) { 1816247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, i); 1826247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes } 1836247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes for (int i = 400; i <= 406; ++i) { 1846247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, i); 1856247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes } 1866247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes // (See test_responseCaching_407.) 1876247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 408); 1886247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 409); 18951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson // (See test_responseCaching_410.) 1906247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes for (int i = 411; i <= 418; ++i) { 1916247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, i); 1926247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes } 1936247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes for (int i = 500; i <= 506; ++i) { 1946247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, i); 1956247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes } 1966247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes } 1976247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes 19851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void test_responseCaching_300() throws Exception { 19951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson // TODO: fix this for android 20051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertCached(false, 300); 20151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 20251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 2036247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes public void test_responseCaching_407() throws Exception { 2046247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes // This test will fail on Android because we throw if we're not using a proxy. 2056247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes // This isn't true of the RI, but it seems like useful debugging behavior. 2066247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertCached(false, 407); 2076247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes } 2086247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes 20951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void test_responseCaching_410() throws Exception { 21051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson // the HTTP spec permits caching 410s, but the RI doesn't. 21151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertCached(false, 410); 21251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 21351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 2146247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes private void assertCached(boolean shouldPut, int responseCode) throws Exception { 21551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server = new MockWebServer(); 216b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.enqueue(new MockResponse() 217b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson .setResponseCode(responseCode) 21851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson .setBody("ABCDE") 219b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson .addHeader("WWW-Authenticate: challenge")); 220b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson server.play(); 221b1b5baac449d2725002338735f4db34bec8fd001Jesse Wilson 22251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson DefaultResponseCache responseCache = new DefaultResponseCache(); 22351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson ResponseCache.setDefault(responseCache); 22451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson URL url = server.getUrl("/"); 22551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 2266247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes assertEquals(responseCode, conn.getResponseCode()); 2276247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes 22851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson // exhaust the content stream 22951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson try { 23051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson // TODO: remove special case once testUnauthorizedResponseHandling() is fixed 23151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson if (responseCode != 401) { 23251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson readAscii(conn.getInputStream(), Integer.MAX_VALUE); 23351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 23451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } catch (IOException ignored) { 23551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 23651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 23751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson Set<URI> expectedCachedUris = shouldPut 23851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson ? Collections.singleton(url.toURI()) 23951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson : Collections.<URI>emptySet(); 24051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(Integer.toString(responseCode), 24151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson expectedCachedUris, responseCache.getContents().keySet()); 24251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.shutdown(); // tearDown() isn't sufficient; this test starts multiple servers 2436247987eb505a482a67f5f19678260d9e7240a5fElliott Hughes } 24460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 24560476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson public void testConnectViaHttps() throws IOException, InterruptedException { 24660476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 24760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 24860476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson server.useHttps(testSSLContext.sslContext.getSocketFactory(), false); 24960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson server.enqueue(new MockResponse() 25060476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson .setResponseCode(200) 25160476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson .setBody("this response comes via HTTPS")); 25260476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson server.play(); 25360476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 25460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson URL url = new URL("https://localhost:" + server.getPort() + "/foo"); 25560476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); 25660476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson connection.setSSLSocketFactory(testSSLContext.sslContext.getSocketFactory()); 25760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 258c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("this response comes via HTTPS", connection); 25960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 26060476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson RecordedRequest request = server.takeRequest(); 26160476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertEquals("GET /foo HTTP/1.1", request.getRequestLine()); 26260476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson } 26360476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 26460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson public void testConnectViaProxy() throws IOException, InterruptedException { 26560476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson MockResponse mockResponse = new MockResponse() 26660476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson .setResponseCode(200) 26760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson .setBody("this response comes via a proxy"); 26851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(mockResponse); 26951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.play(); 27060476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 27160476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson URLConnection connection = new URL("http://android.com/foo").openConnection( 27251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.toProxyAddress()); 273c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("this response comes via a proxy", connection); 27460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 27551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson RecordedRequest request = server.takeRequest(); 27660476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertEquals("GET http://android.com/foo HTTP/1.1", request.getRequestLine()); 27760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertContains(request.getHeaders(), "Host: android.com"); 27860476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson } 27960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 280c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson public void testContentDisagreesWithContentLengthHeader() throws IOException { 281c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.enqueue(new MockResponse() 282c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson .setResponseCode(200) 283c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson .setBody("abc\r\nYOU SHOULD NOT SEE THIS") 284c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson .clearHeaders() 285c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson .addHeader("Content-Length: 3")); 286c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.play(); 287c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 288c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("abc", server.getUrl("/").openConnection()); 289c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson } 290c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 291c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson public void testContentDisagreesWithChunkedHeader() throws IOException { 292c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson MockResponse mockResponse = new MockResponse(); 293c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson mockResponse.setResponseCode(200); 294c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson mockResponse.setChunkedBody("abc", 3); 295c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 296c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson bytesOut.write(mockResponse.getBody()); 297c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson bytesOut.write("\r\nYOU SHOULD NOT SEE THIS".getBytes()); 298c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson mockResponse.setBody(bytesOut.toByteArray()); 299c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson mockResponse.clearHeaders(); 300c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson mockResponse.addHeader("Transfer-encoding: chunked"); 301c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 302c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.enqueue(mockResponse); 303c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson server.play(); 304c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 305c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("abc", server.getUrl("/").openConnection()); 306c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson } 307c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 30860476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson public void testConnectViaHttpProxyToHttps() throws IOException, InterruptedException { 30960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson TestSSLContext testSSLContext = TestSSLContext.create(); 31060476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 31151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.useHttps(testSSLContext.sslContext.getSocketFactory(), true); 31251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(new MockResponse().setResponseCode(200).clearHeaders()); // for CONNECT 31351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(new MockResponse() 31460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson .setResponseCode(200) 31560476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson .setBody("this response comes via a secure proxy")); 31651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.play(); 31760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 31860476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson URL url = new URL("https://android.com/foo"); 31960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson HttpsURLConnection connection = (HttpsURLConnection) url.openConnection( 32051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.toProxyAddress()); 32160476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson connection.setSSLSocketFactory(testSSLContext.sslContext.getSocketFactory()); 32260476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson connection.setHostnameVerifier(new HostnameVerifier() { 32360476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson public boolean verify(String hostname, SSLSession session) { 32460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson return true; 32560476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson } 32660476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson }); 32760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 328c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent("this response comes via a secure proxy", connection); 32960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 33051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson RecordedRequest connect = server.takeRequest(); 33160476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertEquals("Connect line failure on proxy", 33260476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson "CONNECT android.com:443 HTTP/1.1", connect.getRequestLine()); 33360476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertContains(connect.getHeaders(), "Host: android.com"); 33460476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 33551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson RecordedRequest get = server.takeRequest(); 33660476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertEquals("GET /foo HTTP/1.1", get.getRequestLine()); 33760476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertContains(get.getHeaders(), "Host: android.com"); 33860476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson } 33960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson 34051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testResponseCachingAndInputStreamSkipWithFixedLength() throws IOException { 34151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testResponseCaching(TransferKind.FIXED_LENGTH); 34251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 34351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 34451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testResponseCachingAndInputStreamSkipWithChunkedEncoding() throws IOException { 34551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testResponseCaching(TransferKind.CHUNKED); 34651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 34751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 34851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testResponseCachingAndInputStreamSkipWithNoLengthHeaders() throws IOException { 34951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testResponseCaching(TransferKind.END_OF_STREAM); 35051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 35151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 35251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson /** 35351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * HttpURLConnection.getInputStream().skip(long) causes ResponseCache corruption 35451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * http://code.google.com/p/android/issues/detail?id=8175 35551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson */ 35651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private void testResponseCaching(TransferKind transferKind) throws IOException { 35751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson MockResponse response = new MockResponse(); 35851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson transferKind.setBody(response, "I love puppies but hate spiders", 1); 35951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(response); 36051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.play(); 36151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 36251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson DefaultResponseCache cache = new DefaultResponseCache(); 36351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson ResponseCache.setDefault(cache); 36451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 36551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson // Make sure that calling skip() doesn't omit bytes from the cache. 36651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson URLConnection urlConnection = server.getUrl("/").openConnection(); 36751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson InputStream in = urlConnection.getInputStream(); 36851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals("I love ", readAscii(in, "I love ".length())); 36951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson reliableSkip(in, "puppies but hate ".length()); 37051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals("spiders", readAscii(in, "spiders".length())); 37151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(-1, in.read()); 37251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson in.close(); 37351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getSuccessCount()); 37451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 37551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson urlConnection = server.getUrl("/").openConnection(); // this response is cached! 37651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson in = urlConnection.getInputStream(); 37751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals("I love puppies but hate spiders", 37851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson readAscii(in, "I love puppies but hate spiders".length())); 37951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(-1, in.read()); 38051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getMissCount()); 38151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getHitCount()); 38251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 38351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 38451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private void reliableSkip(InputStream in, int length) throws IOException { 38551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson while (length > 0) { 38651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson length -= in.skip(length); 38751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 38851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 38951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 39051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson /** 39151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * Reads {@code count} characters from the stream. If the stream is 39251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * exhausted before {@code count} characters can be read, the remaining 39351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * characters are returned and the stream is closed. 39451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson */ 39551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private String readAscii(InputStream in, int count) throws IOException { 39651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson StringBuilder result = new StringBuilder(); 39751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson for (int i = 0; i < count; i++) { 39851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson int value = in.read(); 39951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson if (value == -1) { 40051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson in.close(); 40151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson break; 40251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 40351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson result.append((char) value); 40451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 40551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson return result.toString(); 40651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 40751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 40851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testServerDisconnectsPrematurelyWithContentLengthHeader() throws IOException { 40951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testServerPrematureDisconnect(TransferKind.FIXED_LENGTH); 41051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 41151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 41251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testServerDisconnectsPrematurelyWithChunkedEncoding() throws IOException { 41351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testServerPrematureDisconnect(TransferKind.CHUNKED); 41451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 41551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 41651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testServerDisconnectsPrematurelyWithNoLengthHeaders() throws IOException { 41751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson /* 41851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * Intentionally empty. This case doesn't make sense because there's no 41951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * such thing as a premature disconnect when the disconnect itself 42051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * indicates the end of the data stream. 42151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson */ 42251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 42351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 42451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private void testServerPrematureDisconnect(TransferKind transferKind) throws IOException { 42551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson MockResponse response = new MockResponse(); 42651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 16); 42751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(truncateViolently(response, 16)); 42851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 42951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.play(); 43051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 43151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson DefaultResponseCache cache = new DefaultResponseCache(); 43251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson ResponseCache.setDefault(cache); 43351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 43451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson BufferedReader reader = new BufferedReader(new InputStreamReader( 43551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.getUrl("/").openConnection().getInputStream())); 43651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals("ABCDE", reader.readLine()); 43751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson try { 43851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson reader.readLine(); 43951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson fail("This implementation silently ignored a truncated HTTP body."); 44051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } catch (IOException expected) { 44151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 44251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 44351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getAbortCount()); 44451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(0, cache.getSuccessCount()); 44551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertContent("Request #2", server.getUrl("/").openConnection()); 44651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getAbortCount()); 44751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getSuccessCount()); 44851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 44951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 45051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testClientPrematureDisconnectWithContentLengthHeader() throws IOException { 45151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testClientPrematureDisconnect(TransferKind.FIXED_LENGTH); 45251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 45351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 45451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testClientPrematureDisconnectWithChunkedEncoding() throws IOException { 45551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testClientPrematureDisconnect(TransferKind.CHUNKED); 45651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 45751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 45851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testClientPrematureDisconnectWithNoLengthHeaders() throws IOException { 45951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testClientPrematureDisconnect(TransferKind.END_OF_STREAM); 46051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 46151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 46251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private void testClientPrematureDisconnect(TransferKind transferKind) throws IOException { 46351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson MockResponse response = new MockResponse(); 46451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson transferKind.setBody(response, "ABCDE\nFGHIJKLMNOPQRSTUVWXYZ", 1024); 46551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(response); 46651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(new MockResponse().setBody("Request #2")); 46751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.play(); 46851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 46951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson DefaultResponseCache cache = new DefaultResponseCache(); 47051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson ResponseCache.setDefault(cache); 47151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 47251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson InputStream in = server.getUrl("/").openConnection().getInputStream(); 47351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals("ABCDE", readAscii(in, 5)); 47451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson in.close(); 47551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson try { 47651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson in.read(); 47751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson fail("Expected an IOException because the stream is closed."); 47851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } catch (IOException expected) { 47951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 48051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 48151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getAbortCount()); 48251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(0, cache.getSuccessCount()); 48351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertContent("Request #2", server.getUrl("/").openConnection()); 48451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getAbortCount()); 48551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getSuccessCount()); 48651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 48751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 48851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson /** 48951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * Shortens the body of {@code response} but not the corresponding headers. 49051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * Only useful to test how clients respond to the premature conclusion of 49151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * the HTTP body. 49251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson */ 49351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson private MockResponse truncateViolently(MockResponse response, int numBytesToKeep) { 49451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.setDisconnectAtEnd(true); 49551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson List<String> headers = new ArrayList<String>(response.getHeaders()); 49651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.setBody(Arrays.copyOfRange(response.getBody(), 0, numBytesToKeep)); 49751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.getHeaders().clear(); 49851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.getHeaders().addAll(headers); 49951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson return response; 50051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 50151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 50251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testMarkAndResetWithContentLengthHeader() throws IOException { 50351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testMarkAndReset(TransferKind.FIXED_LENGTH); 50451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 50551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 50651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testMarkAndResetWithChunkedEncoding() throws IOException { 50751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testMarkAndReset(TransferKind.CHUNKED); 50851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 50951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 51051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testMarkAndResetWithNoLengthHeaders() throws IOException { 51151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson testMarkAndReset(TransferKind.END_OF_STREAM); 51251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 51351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 51451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testMarkAndReset(TransferKind transferKind) throws IOException { 51551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson MockResponse response = new MockResponse(); 51651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson transferKind.setBody(response, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1024); 51751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(response); 51851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.play(); 51951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 52051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson DefaultResponseCache cache = new DefaultResponseCache(); 52151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson ResponseCache.setDefault(cache); 52251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 52351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson InputStream in = server.getUrl("/").openConnection().getInputStream(); 52451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertFalse("This implementation claims to support mark().", in.markSupported()); 52551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson in.mark(5); 52651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals("ABCDE", readAscii(in, 5)); 52751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson try { 52851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson in.reset(); 52951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson fail(); 53051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } catch (IOException expected) { 53151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 53251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals("FGHIJKLMNOPQRSTUVWXYZ", readAscii(in, Integer.MAX_VALUE)); 53351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 53451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertContent("ABCDEFGHIJKLMNOPQRSTUVWXYZ", server.getUrl("/").openConnection()); 53551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getSuccessCount()); 53651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, cache.getHitCount()); 53751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 53851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 53951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson /** 54051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * We've had a bug where we forget the HTTP response when we see response 54151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * code 401. This causes a new HTTP request to be issued for every call into 54251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson * the URLConnection. 54351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson */ 54451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson public void testUnauthorizedResponseHandling() throws IOException { 54551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson MockResponse response = new MockResponse() 54651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson .addHeader("WWW-Authenticate: challenge") 54751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson .setResponseCode(401) // UNAUTHORIZED 54851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson .setBody("Unauthorized"); 54951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(response); 55051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(response); 55151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.enqueue(response); 55251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson server.play(); 55351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 55451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson URL url = server.getUrl("/"); 55551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 55651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 55751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(401, conn.getResponseCode()); 55851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(401, conn.getResponseCode()); 55951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(401, conn.getResponseCode()); 56051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(1, server.getRequestCount()); 56151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 56251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 5636906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson public void testNonHexChunkSize() throws IOException { 5646906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson server.enqueue(new MockResponse() 5656906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson .setBody("5\r\nABCDE\r\nG\r\nFGHIJKLMNOPQRSTU\r\n0\r\n\r\n") 5666906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson .clearHeaders() 5676906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson .addHeader("Transfer-encoding: chunked")); 5686906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson server.play(); 5696906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson 5706906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 5716906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson try { 5726906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE); 5736906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson fail(); 5746906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson } catch (IOException e) { 5756906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson } 5766906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson } 5776906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson 5786906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson public void testMissingChunkBody() throws IOException { 5796906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson server.enqueue(new MockResponse() 5806906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson .setBody("5") 5816906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson .clearHeaders() 5826906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson .addHeader("Transfer-encoding: chunked") 5836906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson .setDisconnectAtEnd(true)); 5846906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson server.play(); 5856906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson 5866906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson URLConnection connection = server.getUrl("/").openConnection(); 5876906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson try { 5886906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson readAscii(connection.getInputStream(), Integer.MAX_VALUE); 5896906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson fail(); 5906906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson } catch (IOException e) { 5916906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson } 5926906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson } 5936906b0c12dcf3216883d0373973a252812a20d32Jesse Wilson 594c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson /** 595c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson * Reads at most {@code limit} characters from {@code in} and asserts that 596c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson * content equals {@code expected}. 597c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson */ 598c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson private void assertContent(String expected, URLConnection connection, int limit) 599c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson throws IOException { 60051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson assertEquals(expected, readAscii(connection.getInputStream(), limit)); 601c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson ((HttpURLConnection) connection).disconnect(); 602c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson } 603c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 604c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson private void assertContent(String expected, URLConnection connection) throws IOException { 605c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson assertContent(expected, connection, Integer.MAX_VALUE); 606c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson } 607c8977f474b30c5f3807398859a6b16687af6fc7bJesse Wilson 60860476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson private void assertContains(List<String> headers, String header) { 60960476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson assertTrue(headers.toString(), headers.contains(header)); 61060476787f0e0f052366d8031c74e507ffd3d16a3Jesse Wilson } 61151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 61251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson enum TransferKind { 61351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson CHUNKED() { 61451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson @Override void setBody(MockResponse response, String content, int chunkSize) 61551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson throws IOException { 61651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.setChunkedBody(content, chunkSize); 61751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 61851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson }, 61951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson FIXED_LENGTH() { 62051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson @Override void setBody(MockResponse response, String content, int chunkSize) { 62151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.setBody(content); 62251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 62351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson }, 62451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson END_OF_STREAM() { 62551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson @Override void setBody(MockResponse response, String content, int chunkSize) { 62651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.setBody(content); 62751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson response.setDisconnectAtEnd(true); 62851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson for (Iterator<String> h = response.getHeaders().iterator(); h.hasNext(); ) { 62951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson if (h.next().startsWith("Content-Length:")) { 63051e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson h.remove(); 63151e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson break; 63251e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 63351e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 63451e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 63551e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson }; 63651e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson 63751e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson abstract void setBody(MockResponse response, String content, int chunkSize) 63851e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson throws IOException; 63951e468abf2628ce964d3657042f3ac8f2c947504Jesse Wilson } 640e40c9e3935a5024c0f3ebfb3f1441fcd5c48ed86Elliott Hughes} 641