summaryrefslogtreecommitdiffstats
path: root/luni
diff options
context:
space:
mode:
authorNeil Fuller <nfuller@google.com>2014-02-14 17:25:56 +0000
committerNeil Fuller <nfuller@google.com>2014-02-19 20:19:53 +0000
commit76fafa7b18ae7e977fabb64742fd3c1449ee0f57 (patch)
treef017d9dc4201ad736d91f90dfa38bede9b12f060 /luni
parent2587ef91ba693d73e97704e8163c050b286e7330 (diff)
downloadlibcore-76fafa7b18ae7e977fabb64742fd3c1449ee0f57.zip
libcore-76fafa7b18ae7e977fabb64742fd3c1449ee0f57.tar.gz
libcore-76fafa7b18ae7e977fabb64742fd3c1449ee0f57.tar.bz2
Change HttpsURLConnectionTest for okhttp update.
In preparation for an okhttp update. The test broke with the next okhttp version when tested due to some buffering issue on devices with long user agent strings: with larger user agents the headers would be flushed "early" and the client would only receive the headers and not the body in the single read it does (which broke the test under CTS). With shorter user agents (e.g. "Java0" as used under Vogar) it would buffer everything, send it all and the test would pass. Rather than fix the webserver in the test it has been removed and replaced with one based on MockWebServer. Change-Id: I4ce8558cebb2b87b567c3dbfb75580a575a30946
Diffstat (limited to 'luni')
-rw-r--r--luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https/HttpsURLConnectionTest.java1043
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);
}
}
}