From 51e5320e7be7aaffed13e21f3f44cbd6d67587a8 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sun, 11 Nov 2012 12:45:50 -0800 Subject: [PATCH] Don't drop out of connect if the first request fails. This fixes a break caused by the recent try-harder-on-IP-addresses change, where if the first connect failed we returned rather than trying until we reached a connection or an error. --- .../net/http/HttpURLConnectionImpl.java | 5 +- .../libcore/net/http/URLConnectionTest.java | 73 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/main/java/libcore/net/http/HttpURLConnectionImpl.java b/src/main/java/libcore/net/http/HttpURLConnectionImpl.java index 1b881b491..f5cc49e74 100644 --- a/src/main/java/libcore/net/http/HttpURLConnectionImpl.java +++ b/src/main/java/libcore/net/http/HttpURLConnectionImpl.java @@ -80,7 +80,10 @@ public class HttpURLConnectionImpl extends OkHttpConnection { @Override public final void connect() throws IOException { initHttpEngine(); - execute(false); + boolean success; + do { + success = execute(false); + } while (!success); } @Override public final void disconnect() { diff --git a/src/test/java/libcore/net/http/URLConnectionTest.java b/src/test/java/libcore/net/http/URLConnectionTest.java index 571bcf86e..0c5e13099 100644 --- a/src/test/java/libcore/net/http/URLConnectionTest.java +++ b/src/test/java/libcore/net/http/URLConnectionTest.java @@ -41,7 +41,9 @@ import java.net.InetAddress; import java.net.PasswordAuthentication; import java.net.ProtocolException; import java.net.Proxy; +import java.net.ProxySelector; import java.net.ResponseCache; +import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.net.URI; import java.net.URISyntaxException; @@ -80,6 +82,7 @@ public final class URLConnectionTest extends TestCase { /** base64("username:password") */ private static final String BASE_64_CREDENTIALS = "dXNlcm5hbWU6cGFzc3dvcmQ="; + private ProxySelector defaultProxySelector = ProxySelector.getDefault(); private MockWebServer server = new MockWebServer(); private MockWebServer server2 = new MockWebServer(); @@ -105,6 +108,7 @@ public final class URLConnectionTest extends TestCase { @Override protected void tearDown() throws Exception { ResponseCache.setDefault(null); Authenticator.setDefault(null); + ProxySelector.setDefault(defaultProxySelector); System.clearProperty("proxyHost"); System.clearProperty("proxyPort"); System.clearProperty("http.proxyHost"); @@ -286,6 +290,51 @@ public final class URLConnectionTest extends TestCase { } } + public void testConnectRetriesUntilConnectedOrFailed() throws Exception { + server.play(); + URL url = server.getUrl("/foo"); + server.shutdown(); + + OkHttpConnection connection = openConnection(url); + try { + connection.connect(); + fail(); + } catch (IOException expected) { + } + } + + public void testRequestBodySurvivesRetriesWithFixedLength() throws Exception { + testRequestBodySurvivesRetries(TransferKind.FIXED_LENGTH); + } + + public void testRequestBodySurvivesRetriesWithChunkedStreaming() throws Exception { + testRequestBodySurvivesRetries(TransferKind.CHUNKED); + } + + public void testRequestBodySurvivesRetriesWithBufferedBody() throws Exception { + testRequestBodySurvivesRetries(TransferKind.END_OF_STREAM); + } + + private void testRequestBodySurvivesRetries(TransferKind transferKind) throws Exception { + server.enqueue(new MockResponse().setBody("abc")); + server.play(); + + // Use a misconfigured proxy to guarantee that the request is retried. + server2.play(); + FakeProxySelector proxySelector = new FakeProxySelector(); + proxySelector.proxies.add(server2.toProxyAddress()); + ProxySelector.setDefault(proxySelector); + server2.shutdown(); + + OkHttpConnection connection = openConnection(server.getUrl("/def")); + connection.setDoOutput(true); + transferKind.setForRequest(connection, 4); + connection.getOutputStream().write("body".getBytes("UTF-8")); + assertContent("abc", connection); + + assertEquals("body", server.takeRequest().getUtf8Body()); + } + public void testGetErrorStreamOnSuccessfulRequest() throws Exception { server.enqueue(new MockResponse().setBody("A")); server.play(); @@ -2266,11 +2315,17 @@ public final class URLConnectionTest extends TestCase { throws IOException { response.setChunkedBody(content, chunkSize); } + @Override void setForRequest(OkHttpConnection connection, int contentLength) { + connection.setChunkedStreamingMode(5); + } }, FIXED_LENGTH() { @Override void setBody(MockResponse response, byte[] content, int chunkSize) { response.setBody(content); } + @Override void setForRequest(OkHttpConnection connection, int contentLength) { + connection.setChunkedStreamingMode(contentLength); + } }, END_OF_STREAM() { @Override void setBody(MockResponse response, byte[] content, int chunkSize) { @@ -2283,11 +2338,15 @@ public final class URLConnectionTest extends TestCase { } } } + @Override void setForRequest(OkHttpConnection connection, int contentLength) { + } }; abstract void setBody(MockResponse response, byte[] content, int chunkSize) throws IOException; + abstract void setForRequest(OkHttpConnection connection, int contentLength); + void setBody(MockResponse response, String content, int chunkSize) throws IOException { setBody(response, content.getBytes("UTF-8"), chunkSize); } @@ -2398,4 +2457,18 @@ public final class URLConnectionTest extends TestCase { return authentication; } } + + private static class FakeProxySelector extends ProxySelector { + List proxies = new ArrayList(); + + @Override public List select(URI uri) { + // Don't handle 'socket' schemes, which the RI's Socket class may request (for SOCKS). + return uri.getScheme().equals("http") || uri.getScheme().equals("https") + ? proxies + : Collections.singletonList(Proxy.NO_PROXY); + } + + @Override public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + } + } }