Index: modules/luni/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/http/HttpURLConnectionTest.java =================================================================== --- modules/luni/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/http/HttpURLConnectionTest.java (revision 412668) +++ modules/luni/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/http/HttpURLConnectionTest.java (working copy) @@ -18,51 +18,99 @@ import java.io.IOException; import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; import java.net.ServerSocket; +import java.net.SocketAddress; import java.net.SocketTimeoutException; +import java.net.URI; import java.net.URL; +import java.util.ArrayList; import junit.framework.TestCase; /** * Tests for HTTPURLConnection class constructors and methods. - * + * */ public class HttpURLConnectionTest extends TestCase { - - private final Object bound = new Object(); - //TODO: replace with connection to a mock server - Thread httpServer = new Thread(new Runnable() { + private static int port = 34567; + + private final static Object bound = new Object(); + + static class MockServer extends Thread { + ServerSocket serverSocket; + boolean accepted = false; + + public MockServer(String name) throws IOException { + super(name); + serverSocket = new ServerSocket(0); + serverSocket.setSoTimeout(1000); + } + + public int port() { + return serverSocket.getLocalPort(); + } + public void run() { try { - ServerSocket ss = new ServerSocket(port); - synchronized(bound) { + synchronized (bound) { bound.notify(); } - ss.setSoTimeout(1000); try { - ss.accept().close(); + serverSocket.accept().close(); + accepted = true; } catch (SocketTimeoutException ignore) { } - ss.close(); + serverSocket.close(); } catch (IOException e) { throw new RuntimeException(e); } } - }, "ServerSocket for HttpURLConnectionTest"); - - private int port = 34567; - - public void setUp() throws Exception { - super.setUp(); - httpServer.start(); } - public void tearDown() throws Exception { - super.tearDown(); - httpServer.join(); + /** + * ProxySelector implementation used in the test. + */ + static class TestProxySelector extends ProxySelector { + + // this uri request will go through proxy + private URI uri; + // proxy port + private int proxy_port; + // server port + private int server_port; + + /** + * Creates proxy selector instance. + * Selector will return the proxy, only if the connection + * is made to localhost:server_port. Otherwise it will + * return NO_PROXY. + * Address of the returned proxy will be localhost:proxy_port. + */ + public TestProxySelector(int server_port, int proxy_port) { + this.server_port = server_port; + this.proxy_port = proxy_port; + } + + public java.util.List select(URI uri) { + Proxy proxy = Proxy.NO_PROXY; + if (("localhost".equals(uri.getHost())) + && (server_port == uri.getPort())) { + proxy = new Proxy(Proxy.Type.HTTP, + new InetSocketAddress("localhost", proxy_port)); + } + ArrayList result = new ArrayList(); + result.add(proxy); + return result; + } + + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + // do nothing + } } /** @@ -70,15 +118,103 @@ */ public void testGetOutputStream() throws Exception { // Regression for HARMONY-482 + MockServer httpServer = + new MockServer("ServerSocket for HttpURLConnectionTest"); + httpServer.start(); synchronized(bound) { bound.wait(5000); } - HttpURLConnection c = (HttpURLConnection) new URL("http://127.0.0.1:" - + port).openConnection(); + HttpURLConnection c = (HttpURLConnection) + new URL("http://127.0.0.1:" + httpServer.port()).openConnection(); c.setDoOutput(true); - //use new String("POST") instead of simple "POST" to obtain other - //object instances then those that are in HttpURLConnection classes + //use new String("POST") instead of simple "POST" to obtain other + //object instances then those that are in HttpURLConnection classes c.setRequestMethod(new String("POST")); c.getOutputStream(); + httpServer.join(); } + + + /** + * Test checks if the proxy specified in openConnection + * method will be used for connection to the server + */ + public void testUsingProxy() throws Exception { + // Regression for HARMONY-570 + MockServer server = new MockServer("server"); + MockServer proxy = new MockServer("proxy"); + + URL url = new URL("http://localhost:" + server.port()); + + HttpURLConnection connection = (HttpURLConnection) url + .openConnection(new Proxy(Proxy.Type.HTTP, + new InetSocketAddress("localhost", + proxy.port()))); + connection.setConnectTimeout(2000); + connection.setReadTimeout(2000); + + server.start(); + synchronized(bound) { + bound.wait(5000); + } + proxy.start(); + synchronized(bound) { + bound.wait(5000); + } + + connection.connect(); + + // wait while server and proxy run + server.join(); + proxy.join(); + + assertTrue("Connection does not use proxy", connection.usingProxy()); + assertTrue("Proxy server was not used", proxy.accepted); + } + + /** + * Test checks if the proxy provided by proxy selector + * will be used for connection to the server + */ + public void testUsingProxySelector() throws Exception { + // Regression for HARMONY-570 + MockServer server = new MockServer("server"); + MockServer proxy = new MockServer("proxy"); + + URL url = new URL("http://localhost:" + server.port()); + + // keep default proxy selector + ProxySelector defPS = ProxySelector.getDefault(); + // replace selector + ProxySelector.setDefault( + new TestProxySelector(server.port(), proxy.port())); + + try { + HttpURLConnection connection = + (HttpURLConnection) url.openConnection(); + connection.setConnectTimeout(2000); + connection.setReadTimeout(2000); + + server.start(); + synchronized(bound) { + bound.wait(5000); + } + proxy.start(); + synchronized(bound) { + bound.wait(5000); + } + connection.connect(); + + // wait while server and proxy run + server.join(); + proxy.join(); + + assertTrue("Connection does not use proxy", + connection.usingProxy()); + assertTrue("Proxy server was not used", proxy.accepted); + } finally { + // restore default proxy selector + ProxySelector.setDefault(defPS); + } + } } Index: modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java =================================================================== --- modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java (revision 412668) +++ modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java (working copy) @@ -92,6 +92,8 @@ private boolean hasTriedCache = false; + private boolean usingProxy = false; + private HttpOutputStream os; private boolean sentRequest = false; @@ -523,23 +525,80 @@ if (getFromCache()) { return; } - Socket socket; - int connectTimeout = getConnectTimeout(); - InetAddress host = getHostAddress(); - int port = getHostPort(); - SocketAddress sa = new InetSocketAddress(host, port); - if (null == currentProxy || Proxy.Type.HTTP == currentProxy.type()) { - socket = new Socket(); + // socket to be used for connection + Socket socket = null; + // try to determine: to use the proxy or not + if (proxy != null) { + // try to make the connection to the proxy + // specified in constructor. + // IOException will be thrown in the case of failure + socket = getHTTPConnection(proxy.address()); } else { - socket = new Socket(currentProxy); + // Use system-wide ProxySelect to select proxy list, + // then try to connect via elements in the proxy list. + ProxySelector selector = ProxySelector.getDefault(); + List proxyList = selector.select(uri); + if (proxyList != null) { + for (Proxy selectedProxy: proxyList) { + if (selectedProxy.type() == Proxy.Type.DIRECT) { + // the same as NO_PROXY + continue; + } + try { + socket = getHTTPConnection(selectedProxy); + proxy = selectedProxy; + break; // connected + } catch (IOException e) { + socket = null; + // failed to connect, tell it to the selector + selector.connectFailed( + uri, selectedProxy.address(), e); + } + } + } } - socket.connect(sa, connectTimeout); + if (socket != null) { + // connection was made through the proxy + usingProxy = true; + } else { + // make direct connection + socket = getHTTPConnection( + new InetSocketAddress(url.getHost(), url.getPort())); + } socket.setSoTimeout(getReadTimeout()); connected = true; socketOut = socket.getOutputStream(); is = new BufferedInputStream(socket.getInputStream()); } + + /** + * Returns connected socket to be used for this HTTP connection. + * TODO: implement persistent connections. + */ + protected Socket getHTTPConnection(SocketAddress address) throws IOException { + Socket socket = new Socket(); + socket.connect(address, getConnectTimeout()); + return socket; + } + /** + * Returns connected socket to be used for this HTTP connection. + * TODO: implement persistent connections. + */ + protected Socket getHTTPConnection(Proxy proxy) throws IOException { + Socket socket; + if (proxy.type() == Proxy.Type.HTTP) { + socket = getHTTPConnection(proxy.address()); + } else { + // using DIRECT or SOCKS proxy + socket = new Socket(proxy); + socket.connect( + new InetSocketAddress(url.getHost(), url.getPort()), + getConnectTimeout()); + } + return socket; + } + // Tries to get head and body from cache, return true if has got this time or // already got before private boolean getFromCache() throws IOException { @@ -1194,20 +1253,9 @@ * if a proxy port has been set. */ private int getHostPort() { - if (usingProxy()) { - if (null == currentProxy) { - // get from system property - String portString = getSystemPropertyOrAlternative( - "http.proxyPort", "proxyPort"); - if (portString != null) { - hostPort = Integer.parseInt(portString); - } - } else { - // get from proxy - InetSocketAddress addr = (InetSocketAddress) currentProxy - .address(); - hostPort = addr.getPort(); - } + int hostPort; + if (proxy != null) { + hostPort = ((InetSocketAddress) proxy.address()).getPort(); } else { hostPort = url.getPort(); } @@ -1222,7 +1270,11 @@ * given in the URL or the address of the proxy server. */ private InetAddress getHostAddress() throws IOException { - return InetAddress.getByName(getHostName()); + if (proxy != null) { + return ((InetSocketAddress) proxy.address()).getAddress(); + } else { + return InetAddress.getByName(url.getHost()); + } } /** @@ -1230,21 +1282,11 @@ * in the URL or the name of the proxy server. */ private String getHostName() { - if (proxyName != null) { - return proxyName; + if (proxy != null) { + return ((InetSocketAddress) proxy.address()).getHostName(); + } else { + return url.getHost(); } - if (usingProxy()) { - if (null == currentProxy) { - proxyName = getSystemPropertyOrAlternative("http.proxyHost", - "proxyHost"); - } else { - InetSocketAddress addr = (InetSocketAddress) currentProxy - .address(); - proxyName = addr.getHostName(); - } - return proxyName; - } - return url.getHost(); } private String getSystemPropertyOrAlternative(final String key, @@ -1268,27 +1310,7 @@ * 1.0 and JDK 1.1 */ public boolean usingProxy() { - if (Proxy.NO_PROXY == currentProxy) { - return false; - } - // using proxy if http proxy is set by caller. - if (null != currentProxy && Proxy.Type.HTTP == currentProxy.type()) { - return true; - } - // First check whether the user explicitly set whether to use a proxy. - String proxySet = getSystemProperty("http.proxySet"); - if (proxySet != null) - return proxySet.toLowerCase().equals("true"); - - proxySet = getSystemProperty("proxySet"); - if (proxySet != null) - return proxySet.toLowerCase().equals("true"); - - // The user didn't explicitly set whether to use a proxy. Answer true if - // the user specified a proxyHost. - if (getSystemProperty("http.proxyHost") != null) - return true; - return getSystemProperty("proxyHost") != null; + return usingProxy; } /** @@ -1306,41 +1328,7 @@ } return; } - // Use system-wide ProxySelect to select proxy list, - // then try to connect via elements in the proxy list. - if (null != proxy) { - proxyList = new ArrayList(1); - proxyList.add(proxy); - } else { - proxyList = NetUtil.getProxyList(uri); - } - if (null == proxyList) { - currentProxy = null; - doRequestInternal(); - } else { - // try the proxy list until one of them establish - // the connection successfully. - ProxySelector selector = ProxySelector.getDefault(); - Iterator iter = proxyList.iterator(); - boolean doRequestOK = false; - while (iter.hasNext() && !doRequestOK) { - currentProxy = (Proxy) iter.next(); - try { - doRequestInternal(); - doRequestOK = true; - } catch (IOException ioe) { - // if connect failed, callback method "connectFailed" - // should be invoked. - if (null != selector && Proxy.NO_PROXY != currentProxy) { - selector - .connectFailed(uri, currentProxy.address(), ioe); - } - } - } - if (!doRequestOK) { - throw new IOException(Msg.getString("K0097")); - } - } + doRequestInternal(); } void doRequestInternal() throws IOException {