diff options
author | Neil Fuller <nfuller@google.com> | 2014-02-20 09:49:05 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-02-20 09:49:05 +0000 |
commit | 6d9b21a13ad3e8c2fb82427b1ddb967668425467 (patch) | |
tree | f017d9dc4201ad736d91f90dfa38bede9b12f060 /luni | |
parent | 01252476ca9d5a432e6b69c80284e50f40ce6b22 (diff) | |
parent | 76fafa7b18ae7e977fabb64742fd3c1449ee0f57 (diff) | |
download | libcore-6d9b21a13ad3e8c2fb82427b1ddb967668425467.zip libcore-6d9b21a13ad3e8c2fb82427b1ddb967668425467.tar.gz libcore-6d9b21a13ad3e8c2fb82427b1ddb967668425467.tar.bz2 |
Merge "Change HttpsURLConnectionTest for okhttp update."
Diffstat (limited to 'luni')
-rw-r--r-- | luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https/HttpsURLConnectionTest.java | 1043 |
1 files changed, 467 insertions, 576 deletions
diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https/HttpsURLConnectionTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https/HttpsURLConnectionTest.java index c516f67..5258fd1 100644 --- a/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https/HttpsURLConnectionTest.java +++ b/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https/HttpsURLConnectionTest.java @@ -17,6 +17,12 @@ package org.apache.harmony.luni.tests.internal.net.www.protocol.https; +import com.google.mockwebserver.Dispatcher; +import com.google.mockwebserver.MockResponse; +import com.google.mockwebserver.MockWebServer; +import com.google.mockwebserver.RecordedRequest; +import com.google.mockwebserver.SocketPolicy; + import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -25,7 +31,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.PrintStream; import java.net.Authenticator; import java.net.InetSocketAddress; import java.net.PasswordAuthentication; @@ -36,20 +41,15 @@ import java.net.URL; import java.security.KeyStore; import java.security.cert.Certificate; import java.util.Arrays; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; +import java.util.Collections; +import java.util.LinkedList; + import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; @@ -59,22 +59,26 @@ import libcore.javax.net.ssl.TestTrustManager; /** * Implementation independent test for HttpsURLConnection. - * The test needs certstore file placed in system classpath - * and named as "key_store." + the type of the - * default KeyStore installed in the system in lower case. - * <br> - * For example: if default KeyStore type in the system is BKS - * (i.e. java.security file sets up the property keystore.type=BKS), - * thus classpath should point to the directory with "key_store.bks" - * file. - * <br> - * This certstore file should contain self-signed certificate - * generated by keytool utility in a usual way. - * <br> - * The password to the certstore should be "password" (without quotes). */ public class HttpsURLConnectionTest extends TestCase { + private static final String POST_METHOD = "POST"; + + private static final String GET_METHOD = "GET"; + + /** + * Data to be posted by client to the server when the method is POST. + */ + private static final String POST_DATA = "_.-^ Client's Data ^-._"; + + /** + * The content of the response to be sent during HTTPS session. + */ + private static final String RESPONSE_CONTENT + = "<HTML>\n" + + "<HEAD><TITLE>HTTPS Response Content</TITLE></HEAD>\n" + + "</HTML>"; + // the password to the store private static final String KS_PASSWORD = "password"; @@ -107,7 +111,7 @@ public class HttpsURLConnectionTest extends TestCase { * Checks that HttpsURLConnection's default SSLSocketFactory is operable. */ public void testGetDefaultSSLSocketFactory() throws Exception { - // set up the properties defining the default values needed by SSL stuff + // set up the properties pointing to the key/trust stores setUpStoreProperties(); SSLSocketFactory defaultSSLSF = HttpsURLConnection.getDefaultSSLSocketFactory(); @@ -119,55 +123,58 @@ public class HttpsURLConnectionTest extends TestCase { } public void testHttpsConnection() throws Throwable { - // set up the properties defining the default values needed by SSL stuff + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSL server socket acting as a server SSLContext ctx = getContext(); - ServerSocket ss = ctx.getServerSocketFactory().createServerSocket(0); - // create the HostnameVerifier to check hostname verification - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); + + // create a webserver to check and respond to requests + SingleRequestDispatcher dispatcher = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + MockWebServer webServer = createWebServer(ctx, dispatcher); // create url connection to be tested - URL url = new URL("https://localhost:" + ss.getLocalPort()); + URL url = webServer.getUrl("/"); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(ctx.getSocketFactory()); // perform the interaction between the peers - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); + executeClientRequest(connection, false /* doOutput */); - // check the connection state - checkConnectionStateParameters(connection, peerSocket); + checkConnectionStateParameters(connection, dispatcher.getLastRequest()); // should silently exit connection.connect(); + + webServer.shutdown(); } /** - * Tests the behaviour of HTTPS connection in case of unavailability - * of requested resource. + * Tests the behaviour of HTTPS connection in case of unavailability of requested resource. */ public void testHttpsConnection_Not_Found_Response() throws Throwable { - // set up the properties defining the default values needed by SSL stuff + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSL server socket acting as a server SSLContext ctx = getContext(); - ServerSocket ss = ctx.getServerSocketFactory().createServerSocket(0); - // create the HostnameVerifier to check hostname verification - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); + + // create a webserver to check and respond to requests + SingleRequestDispatcher dispatcher = + new SingleRequestDispatcher(GET_METHOD, NOT_FOUND_CODE); + MockWebServer webServer = createWebServer(ctx, dispatcher); // create url connection to be tested - URL url = new URL("https://localhost:" + ss.getLocalPort()); + URL url = webServer.getUrl("/"); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(ctx.getSocketFactory()); try { - doInteraction(connection, ss, NOT_FOUND_CODE); + executeClientRequest(connection, false /* doOutput */); fail("Expected exception was not thrown."); } catch (FileNotFoundException e) { if (DO_LOG) { @@ -178,94 +185,100 @@ public class HttpsURLConnectionTest extends TestCase { // should silently exit connection.connect(); + + webServer.shutdown(); } /** - * Tests possibility to set up the default SSLSocketFactory - * to be used by HttpsURLConnection. + * Tests possibility to set up the default SSLSocketFactory to be used by HttpsURLConnection. */ public void testSetDefaultSSLSocketFactory() throws Throwable { - // create the SSLServerSocket which will be used by server side + // set up the properties pointing to the key/trust stores + setUpStoreProperties(); + SSLContext ctx = getContext(); - SSLServerSocket ss = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(0); - SSLSocketFactory socketFactory = (SSLSocketFactory) ctx.getSocketFactory(); + SSLSocketFactory socketFactory = ctx.getSocketFactory(); // set up the factory as default HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory); // check the result assertSame("Default SSLSocketFactory differs from expected", - socketFactory, HttpsURLConnection.getDefaultSSLSocketFactory()); + socketFactory, HttpsURLConnection.getDefaultSSLSocketFactory()); - // create the HostnameVerifier to check hostname verification - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the initial default host name verifier. + TestHostnameVerifier initialHostnameVerifier = new TestHostnameVerifier(); + HttpsURLConnection.setDefaultHostnameVerifier(initialHostnameVerifier); + + // create a webserver to check and respond to requests + SingleRequestDispatcher dispatcher = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + MockWebServer webServer = createWebServer(ctx, dispatcher); // create HttpsURLConnection to be tested - URL url = new URL("https://localhost:" + ss.getLocalPort()); + URL url = webServer.getUrl("/"); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); - TestHostnameVerifier hnv_late = new TestHostnameVerifier(); - // late initialization: should not be used for created connection - HttpsURLConnection.setDefaultHostnameVerifier(hnv_late); + // late initialization: this HostnameVerifier should not be used for created connection + TestHostnameVerifier lateHostnameVerifier = new TestHostnameVerifier(); + HttpsURLConnection.setDefaultHostnameVerifier(lateHostnameVerifier); // perform the interaction between the peers - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); - // check the connection state - checkConnectionStateParameters(connection, peerSocket); + executeClientRequest(connection, false /* doOutput */); + checkConnectionStateParameters(connection, dispatcher.getLastRequest()); + // check the verification process - assertTrue("Hostname verification was not done", hnv.verified); + assertTrue("Hostname verification was not done", initialHostnameVerifier.verified); assertFalse("Hostname verification should not be done by this verifier", - hnv_late.verified); + lateHostnameVerifier.verified); // check the used SSLSocketFactory assertSame("Default SSLSocketFactory should be used", - HttpsURLConnection.getDefaultSSLSocketFactory(), - connection.getSSLSocketFactory()); + HttpsURLConnection.getDefaultSSLSocketFactory(), + connection.getSSLSocketFactory()); - // should silently exit - connection.connect(); + webServer.shutdown(); } /** - * Tests possibility to set up the SSLSocketFactory - * to be used by HttpsURLConnection. + * Tests + * {@link javax.net.ssl.HttpsURLConnection#setSSLSocketFactory(javax.net.ssl.SSLSocketFactory)}. */ public void testSetSSLSocketFactory() throws Throwable { - // create the SSLServerSocket which will be used by server side + // set up the properties pointing to the key/trust stores SSLContext ctx = getContext(); - SSLServerSocket ss = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(0); - // create the HostnameVerifier to check hostname verification - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the initial default host name verifier. + TestHostnameVerifier hostnameVerifier = new TestHostnameVerifier(); + HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); + + // create a webserver to check and respond to requests + SingleRequestDispatcher dispatcher = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + MockWebServer webServer = createWebServer(ctx, dispatcher); // create HttpsURLConnection to be tested - URL url = new URL("https://localhost:" + ss.getLocalPort()); + URL url = webServer.getUrl("/"); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); - SSLSocketFactory socketFactory = (SSLSocketFactory) ctx.getSocketFactory(); + // late initialization: should not be used for the created connection. + SSLSocketFactory socketFactory = ctx.getSocketFactory(); connection.setSSLSocketFactory(socketFactory); - TestHostnameVerifier hnv_late = new TestHostnameVerifier(); // late initialization: should not be used for created connection - HttpsURLConnection.setDefaultHostnameVerifier(hnv_late); + TestHostnameVerifier lateHostnameVerifier = new TestHostnameVerifier(); + HttpsURLConnection.setDefaultHostnameVerifier(lateHostnameVerifier); // perform the interaction between the peers - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); - // check the connection state - checkConnectionStateParameters(connection, peerSocket); + executeClientRequest(connection, false /* doOutput */); + checkConnectionStateParameters(connection, dispatcher.getLastRequest()); // check the verification process - assertTrue("Hostname verification was not done", hnv.verified); + assertTrue("Hostname verification was not done", hostnameVerifier.verified); assertFalse("Hostname verification should not be done by this verifier", - hnv_late.verified); + lateHostnameVerifier.verified); // check the used SSLSocketFactory assertNotSame("Default SSLSocketFactory should not be used", - HttpsURLConnection.getDefaultSSLSocketFactory(), - connection.getSSLSocketFactory()); - assertSame("Result differs from expected", - socketFactory, connection.getSSLSocketFactory()); + HttpsURLConnection.getDefaultSSLSocketFactory(), + connection.getSSLSocketFactory()); + assertSame("Result differs from expected", socketFactory, connection.getSSLSocketFactory()); - // should silently exit - connection.connect(); + webServer.shutdown(); } /** @@ -304,97 +317,107 @@ public class HttpsURLConnectionTest extends TestCase { * Tests if setHostnameVerifier() method replaces default verifier. */ public void testSetHostnameVerifier() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - SSLServerSocket ss = (SSLServerSocket) - getContext().getServerSocketFactory().createServerSocket(0); + SSLContext ctx = getContext(); + + TestHostnameVerifier defaultHostnameVerifier = new TestHostnameVerifier(); + HttpsURLConnection.setDefaultHostnameVerifier(defaultHostnameVerifier); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // create a webserver to check and respond to requests + SingleRequestDispatcher dispatcher = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + MockWebServer webServer = createWebServer(ctx, dispatcher); // create HttpsURLConnection to be tested - URL url = new URL("https://localhost:" + ss.getLocalPort()); + URL url = webServer.getUrl("/"); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(getContext().getSocketFactory()); - TestHostnameVerifier hnv_late = new TestHostnameVerifier(); - // replace default verifier - connection.setHostnameVerifier(hnv_late); + // replace the default verifier + TestHostnameVerifier connectionHostnameVerifier = new TestHostnameVerifier(); + connection.setHostnameVerifier(connectionHostnameVerifier); // perform the interaction between the peers and check the results - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); - assertTrue("Hostname verification was not done", hnv_late.verified); + executeClientRequest(connection, false /* doOutput */); + assertTrue("Hostname verification was not done", connectionHostnameVerifier.verified); assertFalse("Hostname verification should not be done by this verifier", - hnv.verified); - checkConnectionStateParameters(connection, peerSocket); + defaultHostnameVerifier.verified); - // should silently exit - connection.connect(); + checkConnectionStateParameters(connection, dispatcher.getLastRequest()); + + webServer.shutdown(); } /** * Tests the behaviour in case of sending the data to the server. */ public void test_doOutput() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - SSLServerSocket ss = (SSLServerSocket) - getContext().getServerSocketFactory().createServerSocket(0); + SSLContext ctx = getContext(); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // create a webserver to check and respond to requests + SingleRequestDispatcher dispatcher = new SingleRequestDispatcher(POST_METHOD, OK_CODE); + MockWebServer webServer = createWebServer(ctx, dispatcher); + + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); // create HttpsURLConnection to be tested - URL url = new URL("https://localhost:" + ss.getLocalPort()); + URL url = webServer.getUrl("/"); HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setSSLSocketFactory(getContext().getSocketFactory()); - connection.setDoOutput(true); // perform the interaction between the peers and check the results - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); - checkConnectionStateParameters(connection, peerSocket); + executeClientRequest(connection, true /* doOutput */); + checkConnectionStateParameters(connection, dispatcher.getLastRequest()); // should silently exit connection.connect(); + + webServer.shutdown(); } /** * Tests HTTPS connection process made through the proxy server. */ public void testProxyConnection() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - ServerSocket ss = new ServerSocket(0); + SSLContext ctx = getContext(); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); + + // create a server that pretends to be both a proxy and then the webserver + // request 1: proxy CONNECT, respond with OK + ProxyConnectDispatcher proxyConnectDispatcher = + new ProxyConnectDispatcher(false /* authenticationRequired */); + // request 2: tunnelled GET, respond with OK + SingleRequestDispatcher getDispatcher = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + DelegatingDispatcher delegatingDispatcher = + new DelegatingDispatcher(proxyConnectDispatcher, getDispatcher); + MockWebServer proxyAndWebServer = createProxyAndWebServer(ctx, delegatingDispatcher); // create HttpsURLConnection to be tested + URL proxyUrl = proxyAndWebServer.getUrl("/"); + InetSocketAddress proxyAddress = new InetSocketAddress("localhost", proxyUrl.getPort()); URL url = new URL("https://requested.host:55556/requested.data"); HttpsURLConnection connection = (HttpsURLConnection) - url.openConnection(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress("localhost", - ss.getLocalPort()))); + url.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddress)); connection.setSSLSocketFactory(getContext().getSocketFactory()); // perform the interaction between the peers and check the results - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); - checkConnectionStateParameters(connection, peerSocket); + executeClientRequest(connection, false /* doOutput */); + checkConnectionStateParameters(connection, getDispatcher.getLastRequest()); // should silently exit connection.connect(); + + proxyAndWebServer.shutdown(); } /** @@ -402,81 +425,105 @@ public class HttpsURLConnectionTest extends TestCase { * Proxy server needs authentication. */ public void testProxyAuthConnection() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - ServerSocket ss = new ServerSocket(0); + SSLContext ctx = getContext(); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); Authenticator.setDefault(new Authenticator() { - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication("user", "password" - .toCharArray()); + return new PasswordAuthentication("user", "password".toCharArray()); } }); + // create a server that pretends to be both a proxy and then the webserver + // request 1: proxy CONNECT, respond with auth challenge + ProxyConnectAuthFailDispatcher authFailDispatcher = new ProxyConnectAuthFailDispatcher(); + // request 2: proxy CONNECT, respond with OK + ProxyConnectDispatcher proxyConnectDispatcher = + new ProxyConnectDispatcher(true /* authenticationRequired */); + // request 3: tunnelled GET, respond with OK + SingleRequestDispatcher getDispatcher = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + DelegatingDispatcher delegatingDispatcher = new DelegatingDispatcher( + authFailDispatcher, proxyConnectDispatcher, getDispatcher); + MockWebServer proxyAndWebServer = createProxyAndWebServer(ctx, delegatingDispatcher); + // create HttpsURLConnection to be tested + URL proxyUrl = proxyAndWebServer.getUrl("/"); + InetSocketAddress proxyAddress = new InetSocketAddress("localhost", proxyUrl.getPort()); URL url = new URL("https://requested.host:55555/requested.data"); HttpsURLConnection connection = (HttpsURLConnection) - url.openConnection(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress("localhost", - ss.getLocalPort()))); + url.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddress)); connection.setSSLSocketFactory(getContext().getSocketFactory()); // perform the interaction between the peers and check the results - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); - checkConnectionStateParameters(connection, peerSocket); + executeClientRequest(connection, false /* doOutput */); + checkConnectionStateParameters(connection, getDispatcher.getLastRequest()); // should silently exit connection.connect(); + + proxyAndWebServer.shutdown(); } /** * Tests HTTPS connection process made through the proxy server. - * 2 HTTPS connections are opened for one URL. For the first time - * the connection is opened through one proxy, - * for the second time through another. + * Two HTTPS connections are opened for one URL: the first time the connection is opened + * through one proxy, the second time it is opened through another. */ public void testConsequentProxyConnection() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - ServerSocket ss = new ServerSocket(0); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // create a server that pretends to be both a proxy and then the webserver + SingleRequestDispatcher getDispatcher1 = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + MockWebServer proxyAndWebServer1 = createProxiedServer(getDispatcher1); // create HttpsURLConnection to be tested + URL proxyUrl1 = proxyAndWebServer1.getUrl("/"); URL url = new URL("https://requested.host:55555/requested.data"); + InetSocketAddress proxyAddress = new InetSocketAddress("localhost", proxyUrl1.getPort()); HttpsURLConnection connection = (HttpsURLConnection) - url.openConnection(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress("localhost", - ss.getLocalPort()))); + url.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddress)); connection.setSSLSocketFactory(getContext().getSocketFactory()); + executeClientRequest(connection, false /* doOutput */); + checkConnectionStateParameters(connection, getDispatcher1.getLastRequest()); - // perform the interaction between the peers and check the results - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss); - checkConnectionStateParameters(connection, peerSocket); + proxyAndWebServer1.shutdown(); - // create another SSLServerSocket which will be used by server side - ss = new ServerSocket(0); + // create another server + SingleRequestDispatcher getDispatcher2 = new SingleRequestDispatcher(GET_METHOD, OK_CODE); + MockWebServer proxyAndWebServer2 = createProxiedServer(getDispatcher2); - connection = (HttpsURLConnection) url.openConnection(new Proxy( - Proxy.Type.HTTP, new InetSocketAddress("localhost", ss.getLocalPort()))); - connection.setSSLSocketFactory(getContext().getSocketFactory()); + // create another HttpsURLConnection to be tested + URL proxyUrl2 = proxyAndWebServer2.getUrl("/"); + InetSocketAddress proxyAddress2 = new InetSocketAddress("localhost", proxyUrl2.getPort()); + HttpsURLConnection connection2 = (HttpsURLConnection) url.openConnection( + new Proxy(Proxy.Type.HTTP, proxyAddress2)); + connection2.setSSLSocketFactory(getContext().getSocketFactory()); // perform the interaction between the peers and check the results - peerSocket = (SSLSocket) doInteraction(connection, ss); - checkConnectionStateParameters(connection, peerSocket); + executeClientRequest(connection2, false /* doOutput */); + checkConnectionStateParameters(connection2, getDispatcher2.getLastRequest()); + + proxyAndWebServer2.shutdown(); + } + + private static MockWebServer createProxiedServer(Dispatcher getDispatcher) + throws Exception { + // request 1: proxy CONNECT, respond with OK + ProxyConnectDispatcher proxyConnectDispatcher = + new ProxyConnectDispatcher(false /* authenticationRequired */); + // request 2: The get dispatcher. + DelegatingDispatcher delegatingDispatcher1 = + new DelegatingDispatcher(proxyConnectDispatcher, getDispatcher); + return createProxyAndWebServer(getContext(), delegatingDispatcher1); } /** @@ -485,37 +532,47 @@ public class HttpsURLConnectionTest extends TestCase { * Client sends data to the server. */ public void testProxyAuthConnection_doOutput() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - ServerSocket ss = new ServerSocket(0); + SSLContext ctx = getContext(); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); Authenticator.setDefault(new Authenticator() { - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication("user", "password" - .toCharArray()); + return new PasswordAuthentication("user", "password".toCharArray()); } }); + // create a server that pretends to be both a proxy and then the webserver + // request 1: proxy CONNECT, respond with auth challenge + ProxyConnectAuthFailDispatcher authFailDispatcher = new ProxyConnectAuthFailDispatcher(); + // request 2: proxy CONNECT, respond with OK + ProxyConnectDispatcher proxyConnectDispatcher = + new ProxyConnectDispatcher(true /* authenticationRequired */); + // request 3: tunnelled POST, respond with OK + SingleRequestDispatcher postDispatcher = new SingleRequestDispatcher(POST_METHOD, OK_CODE); + DelegatingDispatcher delegatingDispatcher = new DelegatingDispatcher( + authFailDispatcher, proxyConnectDispatcher, postDispatcher); + MockWebServer proxyAndWebServer = createProxyAndWebServer(ctx, delegatingDispatcher); + URL proxyUrl = proxyAndWebServer.getUrl("/"); + // create HttpsURLConnection to be tested - URL url = new URL("https://requested.host:55554/requested.data"); + InetSocketAddress proxyAddress = new InetSocketAddress("localhost", proxyUrl.getPort()); HttpsURLConnection connection = (HttpsURLConnection) - url.openConnection(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress("localhost", - ss.getLocalPort()))); + proxyUrl.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddress)); connection.setSSLSocketFactory(getContext().getSocketFactory()); - connection.setDoOutput(true); // perform the interaction between the peers and check the results - SSLSocket peerSocket = (SSLSocket) doInteraction(connection, ss, OK_CODE, true); - checkConnectionStateParameters(connection, peerSocket); + executeClientRequest(connection, true /* doOutput */); + checkConnectionStateParameters(connection, postDispatcher.getLastRequest()); + + // should silently exit + connection.connect(); + + proxyAndWebServer.shutdown(); } /** @@ -524,79 +581,82 @@ public class HttpsURLConnectionTest extends TestCase { * (Authenticator was not set up in the system). */ public void testProxyAuthConnectionFailed() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - ServerSocket ss = new ServerSocket(0); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // create a server that pretends to be both a proxy that requests authentication. + MockWebServer proxyAndWebServer = new MockWebServer(); + ProxyConnectAuthFailDispatcher authFailDispatcher = new ProxyConnectAuthFailDispatcher(); + proxyAndWebServer.setDispatcher(authFailDispatcher); + proxyAndWebServer.play(); // create HttpsURLConnection to be tested + URL proxyUrl = proxyAndWebServer.getUrl("/"); + InetSocketAddress proxyAddress = new InetSocketAddress("localhost", proxyUrl.getPort()); URL url = new URL("https://requested.host:55555/requested.data"); HttpsURLConnection connection = (HttpsURLConnection) - url.openConnection(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress("localhost", - ss.getLocalPort()))); + url.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddress)); connection.setSSLSocketFactory(getContext().getSocketFactory()); // perform the interaction between the peers and check the results try { - doInteraction(connection, ss, AUTHENTICATION_REQUIRED_CODE, true); + executeClientRequest(connection, false); } catch (IOException e) { // SSL Tunnelling failed if (DO_LOG) { - System.out.println("Got expected IOException: " - + e.getMessage()); + System.out.println("Got expected IOException: " + e.getMessage()); } } } /** - * Tests the behaviour of HTTPS connection in case of unavailability - * of requested resource. + * Tests the behaviour of HTTPS connection in case of unavailability of requested resource (as + * reported by the target web server). */ public void testProxyConnection_Not_Found_Response() throws Throwable { - // setting up the properties pointing to the key/trust stores + // set up the properties pointing to the key/trust stores setUpStoreProperties(); - // create the SSLServerSocket which will be used by server side - ServerSocket ss = new ServerSocket(0); + SSLContext ctx = getContext(); - // create the HostnameVerifier to check that Hostname verification - // is done - TestHostnameVerifier hnv = new TestHostnameVerifier(); - HttpsURLConnection.setDefaultHostnameVerifier(hnv); + // set the HostnameVerifier required to satisfy SSL - always returns "verified". + HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier()); + + // create a server that pretends to be a proxy + ProxyConnectDispatcher proxyConnectDispatcher = + new ProxyConnectDispatcher(false /* authenticationRequired */); + SingleRequestDispatcher notFoundDispatcher = + new SingleRequestDispatcher(GET_METHOD, NOT_FOUND_CODE); + DelegatingDispatcher delegatingDispatcher = + new DelegatingDispatcher(proxyConnectDispatcher, notFoundDispatcher); + MockWebServer proxyAndWebServer = createProxyAndWebServer(ctx, delegatingDispatcher); // create HttpsURLConnection to be tested - URL url = new URL("https://localhost:" + ss.getLocalPort()); + URL proxyUrl = proxyAndWebServer.getUrl("/"); + InetSocketAddress proxyAddress = new InetSocketAddress("localhost", proxyUrl.getPort()); + URL url = new URL("https://requested.host:55555/requested.data"); HttpsURLConnection connection = (HttpsURLConnection) - url.openConnection(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress("localhost", - ss.getLocalPort()))); + url.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddress)); connection.setSSLSocketFactory(getContext().getSocketFactory()); try { - doInteraction(connection, ss, NOT_FOUND_CODE); // NOT FOUND + executeClientRequest(connection, false /* doOutput */); fail("Expected exception was not thrown."); } catch (FileNotFoundException e) { if (DO_LOG) { - System.out.println("Expected exception was thrown: " - + e.getMessage()); + System.out.println("Expected exception was thrown: " + e.getMessage()); } } } - /** - * Log the name of the test case to be executed. - */ public void setUp() throws Exception { super.setUp(); if (DO_LOG) { + // Log the name of the test case to be executed. System.out.println(); System.out.println("------------------------"); System.out.println("------ " + getName()); @@ -604,8 +664,8 @@ public class HttpsURLConnectionTest extends TestCase { } if (store != null) { - String ksFileName = ("org/apache/harmony/luni/tests/key_store." - + KeyStore.getDefaultType().toLowerCase()); + String ksFileName = "org/apache/harmony/luni/tests/key_store." + + KeyStore.getDefaultType().toLowerCase(); InputStream in = getClass().getClassLoader().getResourceAsStream(ksFileName); FileOutputStream out = new FileOutputStream(store); BufferedInputStream bufIn = new BufferedInputStream(in, 8192); @@ -627,28 +687,21 @@ public class HttpsURLConnectionTest extends TestCase { } } - /** - * Checks the HttpsURLConnection getter's values and compares - * them with actual corresponding values of remote peer. - */ - public static void checkConnectionStateParameters( - HttpsURLConnection clientConnection, SSLSocket serverPeer) - throws Exception { - SSLSession session = serverPeer.getSession(); - - assertEquals(session.getCipherSuite(), clientConnection.getCipherSuite()); - assertEquals(session.getLocalPrincipal(), clientConnection.getPeerPrincipal()); - assertEquals(session.getPeerPrincipal(), clientConnection.getLocalPrincipal()); + private static void checkConnectionStateParameters( + HttpsURLConnection connection, RecordedRequest request) throws Exception { + assertEquals(request.getSslCipherSuite(), connection.getCipherSuite()); + assertEquals(request.getSslLocalPrincipal(), connection.getPeerPrincipal()); + assertEquals(request.getSslPeerPrincipal(), connection.getLocalPrincipal()); - Certificate[] serverCertificates = clientConnection.getServerCertificates(); - Certificate[] localCertificates = session.getLocalCertificates(); + Certificate[] serverCertificates = connection.getServerCertificates(); + Certificate[] localCertificates = request.getSslLocalCertificates(); assertTrue("Server certificates differ from expected", - Arrays.equals(serverCertificates, localCertificates)); + Arrays.equals(serverCertificates, localCertificates)); - localCertificates = clientConnection.getLocalCertificates(); - serverCertificates = session.getPeerCertificates(); + localCertificates = connection.getLocalCertificates(); + serverCertificates = request.getSslPeerCertificates(); assertTrue("Local certificates differ from expected", - Arrays.equals(serverCertificates, localCertificates)); + Arrays.equals(serverCertificates, localCertificates)); } /** @@ -714,395 +767,233 @@ public class HttpsURLConnectionTest extends TestCase { } /** - * Performs interaction between client's HttpsURLConnection and - * servers side (ServerSocket). + * The host name verifier used in test. */ - public static Socket doInteraction(final HttpsURLConnection clientConnection, - final ServerSocket serverSocket) - throws Throwable { - return doInteraction(clientConnection, serverSocket, OK_CODE, false); + static class TestHostnameVerifier implements HostnameVerifier { + + boolean verified = false; + + public boolean verify(String hostname, SSLSession session) { + if (DO_LOG) { + System.out.println("***> verification " + hostname + " " + + session.getPeerHost()); + } + verified = true; + return true; + } } /** - * Performs interaction between client's HttpsURLConnection and - * servers side (ServerSocket). Server will response with specified - * response code. + * Creates a {@link MockWebServer} that acts as both a proxy and then a web server with the + * supplied {@link SSLContext} and {@link Dispatcher}. The dispatcher provided must handle the + * CONNECT request/responses and {@link SocketPolicy} needed to simulate the hand-off from proxy + * to web server. See {@link HttpsURLConnectionTest.ProxyConnectDispatcher}. */ - public static Socket doInteraction(final HttpsURLConnection clientConnection, - final ServerSocket serverSocket, - final int responseCode) - throws Throwable { - return doInteraction(clientConnection, serverSocket, responseCode, false); + private static MockWebServer createProxyAndWebServer(SSLContext ctx, Dispatcher dispatcher) + throws IOException { + return createServer(ctx, dispatcher, true /* handleProxying */); } /** - * Performs interaction between client's HttpsURLConnection and - * servers side (ServerSocket). Server will response with specified - * response code. - * @param doAuthentication specifies - * if the server needs client authentication. + * Creates a {@link MockWebServer} that acts as (only) a web server with the supplied + * {@link SSLContext} and {@link Dispatcher}. */ - public static Socket doInteraction(final HttpsURLConnection clientConnection, - final ServerSocket serverSocket, - final int responseCode, - final boolean doAuthentication) - throws Throwable { - // set up the connection - clientConnection.setDoInput(true); - clientConnection.setConnectTimeout(TIMEOUT); - clientConnection.setReadTimeout(TIMEOUT); + private static MockWebServer createWebServer(SSLContext ctx, Dispatcher dispatcher) + throws IOException { + return createServer(ctx, dispatcher, false /* handleProxying */); + } - ServerWork server = new ServerWork(serverSocket, responseCode, doAuthentication); + private static MockWebServer createServer( + SSLContext ctx, Dispatcher dispatcher, boolean handleProxying) + throws IOException { + MockWebServer webServer = new MockWebServer(); + webServer.useHttps(ctx.getSocketFactory(), handleProxying /* tunnelProxy */); + webServer.setDispatcher(dispatcher); + webServer.play(); + return webServer; + } - ClientConnectionWork client = new ClientConnectionWork(clientConnection); + /** + * A {@link Dispatcher} that has a list of dispatchers to delegate to, each of which will be + * used for one request and then discarded. + */ + private static class DelegatingDispatcher extends Dispatcher { + private LinkedList<Dispatcher> delegates = new LinkedList<Dispatcher>(); - ExecutorService executorService = Executors.newFixedThreadPool(2); - try { - Future<Void> serverFuture = executorService.submit(server); - Future<Void> clientFuture = executorService.submit(client); - - Throwable t = null; - try { - serverFuture.get(30, TimeUnit.SECONDS); - } catch (ExecutionException e) { - t = e.getCause(); - } - try { - clientFuture.get(30, TimeUnit.SECONDS); - } catch (ExecutionException e) { - // two problems? log the first before overwriting - if (t != null) { - t.printStackTrace(); - } - t = e.getCause(); - } - if (t != null) { - throw t; - } - } catch (ExecutionException e) { - throw e.getCause(); - } finally { - executorService.shutdown(); + public DelegatingDispatcher(Dispatcher... dispatchers) { + addAll(dispatchers); + } + + private void addAll(Dispatcher... dispatchers) { + Collections.addAll(delegates, dispatchers); + } + + @Override + public MockResponse dispatch(RecordedRequest request) throws InterruptedException { + return delegates.removeFirst().dispatch(request); } - return server.peerSocket; + @Override + public SocketPolicy peekSocketPolicy() { + return delegates.getFirst().peekSocketPolicy(); + } } - /** - * The host name verifier used in test. - */ - static class TestHostnameVerifier implements HostnameVerifier { + /** Handles a request for SSL tunnel: Answers with a request to authenticate. */ + private static class ProxyConnectAuthFailDispatcher extends Dispatcher { - boolean verified = false; + @Override + public MockResponse dispatch(RecordedRequest request) throws InterruptedException { + assertEquals("CONNECT", request.getMethod()); - public boolean verify(String hostname, SSLSession session) { - if (DO_LOG) { - System.out.println("***> verification " + hostname + " " - + session.getPeerHost()); - } - verified = true; - return true; + MockResponse response = new MockResponse(); + response.setResponseCode(AUTHENTICATION_REQUIRED_CODE); + response.addHeader("Proxy-authenticate: Basic realm=\"localhost\""); + log("Authentication required. Sending response: " + response); + return response; + } + + private void log(String msg) { + HttpsURLConnectionTest.log("ProxyConnectAuthFailDispatcher", msg); } } /** - * The base class for mock Client and Server. + * Handles a request for SSL tunnel: Answers with a success and the socket is upgraded to SSL. */ - static class Work { - - /** - * The header of OK HTTP response. - */ - static final String responseHead = "HTTP/1.1 200 OK\r\n"; - - /** - * The response message to be sent to the proxy CONNECT request. - */ - static final String proxyResponse = responseHead + "\r\n"; - - /** - * The content of the response to be sent during HTTPS session. - */ - static final String httpsResponseContent - = "<HTML>\n" - + "<HEAD><TITLE>HTTPS Response Content</TITLE></HEAD>\n" - + "</HTML>"; - - /** - * The tail of the response to be sent during HTTPS session. - */ - static final String httpsResponseTail - = "Content-type: text/html\r\n" - + "Content-length: " + httpsResponseContent.length() + "\r\n" - + "\r\n" - + httpsResponseContent; - - /** - * The response requiring client's proxy authentication. - */ - static final String respAuthenticationRequired - = "HTTP/1.0 407 Proxy authentication required\r\n" - + "Proxy-authenticate: Basic realm=\"localhost\"\r\n" - + "\r\n"; - - /** - * The data to be posted by client to the server. - */ - static final String clientsData = "_.-^ Client's Data ^-._"; - - /** - * The print stream used for debug log. - * If it is null debug info will not be printed. - */ - private PrintStream out = System.out; - - /** - * Prints log message. - */ - public synchronized void log(String message) { - if (DO_LOG && (out != null)) { - out.println("[" + this + "]: " + message); + private static class ProxyConnectDispatcher extends Dispatcher { + + private final boolean authenticationRequired; + + private ProxyConnectDispatcher(boolean authenticationRequired) { + this.authenticationRequired = authenticationRequired; + } + + @Override + public MockResponse dispatch(RecordedRequest request) throws InterruptedException { + if (authenticationRequired) { + // check provided authorization credentials + assertNotNull("no proxy-authorization credentials: " + request, + request.getHeader("proxy-authorization")); + log("Got authenticated request:\n" + request); + log("------------------"); } + + assertEquals("CONNECT", request.getMethod()); + log("Send proxy response"); + MockResponse response = new MockResponse(); + response.setResponseCode(200); + response.setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END); + return response; + } + + @Override + public SocketPolicy peekSocketPolicy() { + return SocketPolicy.UPGRADE_TO_SSL_AT_END; + } + + private void log(String msg) { + HttpsURLConnectionTest.log("ProxyConnectDispatcher", msg); } } /** - * The class used for server side works. + * Handles a request: Answers with a response with a specified status code. + * If the {@code expectedMethod} is {@code POST} a hardcoded response body {@link #POST_DATA} + * will be included in the response. */ - static class ServerWork extends Work implements Callable<Void> { - - // the server socket used for connection - private final ServerSocket serverSocket; + private static class SingleRequestDispatcher extends Dispatcher { - // indicates if the server acts as proxy server - private final boolean actAsProxy; - - // indicates if the server needs proxy authentication - private final boolean needProxyAuthentication; - - // response code to be send to the client peer + private final String expectedMethod; private final int responseCode; - // the socket connected with client peer - private Socket peerSocket; - - /** - * Creates the thread acting as a server side. - * @param serverSocket the server socket to be used during connection - * @param responseCode the response code to be sent to the client - * @param needProxyAuthentication - * indicates if the server needs proxy authentication - */ - public ServerWork(ServerSocket serverSocket, - int responseCode, - boolean needProxyAuthentication) { - this.serverSocket = serverSocket; + private RecordedRequest lastRequest; + + private SingleRequestDispatcher(String expectedMethod, int responseCode) { this.responseCode = responseCode; - this.needProxyAuthentication = needProxyAuthentication; - // will act as a proxy server if the specified server socket - // is not a secure server socket - this.actAsProxy = !(serverSocket instanceof SSLServerSocket); - if (!actAsProxy) { - // demand client to send its certificate - ((SSLServerSocket) serverSocket).setNeedClientAuth(true); - } + this.expectedMethod = expectedMethod; } - /** - * Closes the connection. - */ - public void closeSocket(Socket socket) { - if (socket == null) { - return; + @Override + public MockResponse dispatch(RecordedRequest request) throws InterruptedException { + if (lastRequest != null) { + fail("More than one request received"); } - try { - socket.getInputStream().close(); - } catch (IOException e) {} - try { - socket.getOutputStream().close(); - } catch (IOException e) {} - try { - socket.close(); - } catch (IOException e) {} + log("Request received: " + request); + lastRequest = request; + assertEquals(expectedMethod, request.getMethod()); + if (POST_METHOD.equals(expectedMethod)) { + assertEquals(POST_DATA, request.getUtf8Body()); + } + + MockResponse response = new MockResponse(); + response.setResponseCode(responseCode); + response.setBody(RESPONSE_CONTENT); + + log("Responding with: " + response); + return response; } - /** - * Performs the actual server work. - * If some exception occurs during the work it will be - * stored in the <code>thrown</code> field. - */ - public Void call() throws Exception { - // the buffer used for reading the messages - byte[] buff = new byte[2048]; - // the number of bytes read into the buffer - try { - // configure the server socket to avoid blocking - serverSocket.setSoTimeout(TIMEOUT); - // accept client connection - peerSocket = serverSocket.accept(); - // configure the client connection to avoid blocking - peerSocket.setSoTimeout(TIMEOUT); - log("Client connection ACCEPTED"); - - InputStream is = peerSocket.getInputStream(); - OutputStream os = peerSocket.getOutputStream(); - - int num = is.read(buff); - if (num == -1) { - log("Unexpected EOF"); - return null; - } - - String message = new String(buff, 0, num); - log("Got request:\n" + message); - log("------------------"); + public RecordedRequest getLastRequest() { + return lastRequest; + } - if (!actAsProxy) { - // Act as Server (not Proxy) side - if (message.startsWith("POST")) { - // client connection sent some data - log("try to read client data"); - String data = message.substring(message.indexOf("\r\n\r\n")+4); - log("client's data: '" + data + "'"); - // check the received data - assertEquals(clientsData, data); - } - } else { - if (needProxyAuthentication) { - // Do proxy work - log("Authentication required..."); - // send Authentication Request - os.write(respAuthenticationRequired.getBytes()); - // read request - num = is.read(buff); - if (num == -1) { - // this connection was closed, - // do clean up and create new one: - closeSocket(peerSocket); - peerSocket = serverSocket.accept(); - peerSocket.setSoTimeout(TIMEOUT); - log("New client connection ACCEPTED"); - is = peerSocket.getInputStream(); - os = peerSocket.getOutputStream(); - num = is.read(buff); - } - message = new String(buff, 0, num); - log("Got authenticated request:\n" + message); - log("------------------"); - // check provided authorization credentials - assertTrue("no proxy-authorization credentials: " + message, - message.toLowerCase().indexOf("proxy-authorization:") != -1); - } - - assertTrue(message.startsWith("CONNECT")); - // request for SSL tunnel - log("Send proxy response"); - os.write(proxyResponse.getBytes()); - - log("Perform SSL Handshake..."); - // create sslSocket acting as a remote server peer - SSLSocket sslSocket = (SSLSocket) - getContext().getSocketFactory().createSocket(peerSocket, - "localhost", - peerSocket.getPort(), - true); // do autoclose - sslSocket.setUseClientMode(false); - // demand client authentication - sslSocket.setNeedClientAuth(true); - sslSocket.startHandshake(); - peerSocket = sslSocket; - is = peerSocket.getInputStream(); - os = peerSocket.getOutputStream(); - - // read the HTTP request sent by secure connection - // (HTTPS request) - num = is.read(buff); - message = new String(buff, 0, num); - log("[Remote Server] Request from SSL tunnel:\n" + message); - log("------------------"); - - if (message.startsWith("POST")) { - // client connection sent some data - log("[Remote Server] try to read client data"); - String data = message.substring(message.indexOf("\r\n\r\n")+4); - log("[Remote Server] client's data: '" + message + "'"); - // check the received data - assertEquals(clientsData, data); - } - - log("[Remote Server] Sending the response by SSL tunnel..."); - } - - // send the response with specified response code - os.write(("HTTP/1.1 " + responseCode - + " Message\r\n" + httpsResponseTail).getBytes()); - os.flush(); - os.close(); - log("Work is DONE actAsProxy=" + actAsProxy); - return null; - } finally { - closeSocket(peerSocket); - try { - serverSocket.close(); - } catch (IOException e) {} - } + @Override + public SocketPolicy peekSocketPolicy() { + return SocketPolicy.DISCONNECT_AT_END; } - @Override public String toString() { - return actAsProxy ? "Proxy Server" : "Server"; + private void log(String msg) { + HttpsURLConnectionTest.log("SingleRequestDispatcher", msg); } } /** - * The class used for client side work. + * Executes an HTTP request using the supplied connection. If {@code doOutput} is {@code true} + * the request made is a POST and the request body sent is {@link #POST_DATA}. + * If {@code doOutput} is {@code false} the request made is a GET. The response must be a + * success with a body {@link #RESPONSE_CONTENT}. */ - static class ClientConnectionWork extends Work implements Callable<Void> { - - // connection to be used to contact the server side - private HttpsURLConnection connection; - - /** - * Creates the thread acting as a client side. - * @param connection connection to be used to contact the server side - */ - public ClientConnectionWork(HttpsURLConnection connection) { - this.connection = connection; - log("Created over connection: " + connection.getClass()); - } + private static void executeClientRequest( + HttpsURLConnection connection, boolean doOutput) throws IOException { - /** - * Performs the actual client work. - * If some exception occurs during the work it will be - * stored in the <code>thrown<code> field. - */ - public Void call() throws Exception { - log("Opening the connection to " + connection.getURL()); - connection.connect(); - log("Connection has been ESTABLISHED, using proxy: " + connection.usingProxy()); - if (connection.getDoOutput()) { - log("Posting data"); - // connection configured to post data, do so - connection.getOutputStream().write(clientsData.getBytes()); - } - // read the content of HTTP(s) response - InputStream is = connection.getInputStream(); - log("Input Stream obtained"); - byte[] buff = new byte[2048]; - int num = 0; - int byt = 0; - while ((num < buff.length) && ((byt = is.read()) != -1)) { - buff[num++] = (byte) byt; - } - String message = new String(buff, 0, num); - log("Got content:\n" + message); - log("------------------"); - log("Response code: " + connection.getResponseCode()); - assertEquals(httpsResponseContent, message); - return null; + // set up the connection + connection.setDoInput(true); + connection.setConnectTimeout(TIMEOUT); + connection.setReadTimeout(TIMEOUT); + connection.setDoOutput(doOutput); + + log("Client", "Opening the connection to " + connection.getURL()); + connection.connect(); + log("Client", "Connection has been ESTABLISHED, using proxy: " + connection.usingProxy()); + if (doOutput) { + log("Client", "Posting data"); + // connection configured to post data, do so + OutputStream os = connection.getOutputStream(); + os.write(POST_DATA.getBytes()); + } + // read the content of HTTP(s) response + InputStream is = connection.getInputStream(); + log("Client", "Input Stream obtained"); + byte[] buff = new byte[2048]; + int num = 0; + int byt; + while ((num < buff.length) && ((byt = is.read()) != -1)) { + buff[num++] = (byte) byt; } + String message = new String(buff, 0, num); + log("Client", "Got content:\n" + message); + log("Client", "------------------"); + log("Client", "Response code: " + connection.getResponseCode()); + assertEquals(RESPONSE_CONTENT, message); + } - @Override public String toString() { - return "Client Connection"; + /** + * Prints log message. + */ + public static synchronized void log(String origin, String message) { + if (DO_LOG) { + System.out.println("[" + origin + "]: " + message); } } } |