8166530: sun/net/www/protocol/https/HttpsClient/ProxyAuthTest.java fails intermittently
Reviewed-by: chegar
--- a/jdk/test/javax/net/ssl/templates/SSLTest.java Thu Oct 20 18:35:45 2016 +0100
+++ b/jdk/test/javax/net/ssl/templates/SSLTest.java Thu Oct 20 11:23:41 2016 -0700
@@ -94,12 +94,22 @@
/*
* Is the server ready to serve?
*/
- private final CountDownLatch serverCondition = new CountDownLatch(1);
+ private final CountDownLatch serverReadyCondition = new CountDownLatch(1);
/*
* Is the client ready to handshake?
*/
- private final CountDownLatch clientCondition = new CountDownLatch(1);
+ private final CountDownLatch clientReadyCondition = new CountDownLatch(1);
+
+ /*
+ * Is the server done?
+ */
+ private final CountDownLatch serverDoneCondition = new CountDownLatch(1);
+
+ /*
+ * Is the client done?
+ */
+ private final CountDownLatch clientDoneCondition = new CountDownLatch(1);
/*
* Public API.
@@ -162,6 +172,25 @@
return keystore;
}
+ // Try to accept a connection in 30 seconds.
+ public static SSLSocket accept(SSLServerSocket sslServerSocket)
+ throws IOException {
+
+ return accept(sslServerSocket, SERVER_TIMEOUT);
+ }
+
+ public static SSLSocket accept(SSLServerSocket sslServerSocket, int timeout)
+ throws IOException {
+
+ try {
+ sslServerSocket.setSoTimeout(timeout);
+ return (SSLSocket) sslServerSocket.accept();
+ } catch (SocketTimeoutException ste) {
+ sslServerSocket.close();
+ return null;
+ }
+ }
+
public SSLTest setSeparateServerThread(boolean separateServerThread) {
this.separateServerThread = separateServerThread;
return this;
@@ -202,33 +231,61 @@
}
public void signalServerReady() {
- serverCondition.countDown();
+ serverReadyCondition.countDown();
+ }
+
+ public void signalServerDone() {
+ serverDoneCondition.countDown();
}
public boolean waitForClientSignal(long timeout, TimeUnit unit)
throws InterruptedException {
- return clientCondition.await(timeout, unit);
+ return clientReadyCondition.await(timeout, unit);
}
public boolean waitForClientSignal() throws InterruptedException {
return waitForClientSignal(CLIENT_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
}
+ public boolean waitForClientDone(long timeout, TimeUnit unit)
+ throws InterruptedException {
+
+ return clientDoneCondition.await(timeout, unit);
+ }
+
+ public boolean waitForClientDone() throws InterruptedException {
+ return waitForClientDone(CLIENT_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
+ }
+
public void signalClientReady() {
- clientCondition.countDown();
+ clientReadyCondition.countDown();
+ }
+
+ public void signalClientDone() {
+ clientDoneCondition.countDown();
}
public boolean waitForServerSignal(long timeout, TimeUnit unit)
throws InterruptedException {
- return serverCondition.await(timeout, unit);
+ return serverReadyCondition.await(timeout, unit);
}
public boolean waitForServerSignal() throws InterruptedException {
return waitForServerSignal(SERVER_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
}
+ public boolean waitForServerDone(long timeout, TimeUnit unit)
+ throws InterruptedException {
+
+ return serverDoneCondition.await(timeout, unit);
+ }
+
+ public boolean waitForServerDone() throws InterruptedException {
+ return waitForServerDone(SERVER_SIGNAL_TIMEOUT, TimeUnit.SECONDS);
+ }
+
public SSLTest setServerPeer(Peer serverPeer) {
this.serverPeer = serverPeer;
return this;
@@ -310,19 +367,14 @@
test.signalServerReady();
// Try to accept a connection in 30 seconds.
- SSLSocket sslSocket;
- try {
- sslServerSocket.setSoTimeout(SERVER_TIMEOUT);
- sslSocket = (SSLSocket) sslServerSocket.accept();
- print("Server accepted connection");
- } catch (SocketTimeoutException ste) {
- sslServerSocket.close();
-
+ SSLSocket sslSocket = accept(sslServerSocket);
+ if (sslSocket == null) {
// Ignore the test case if no connection within 30 seconds.
print("No incoming client connection in 30 seconds. "
- + "Ignore in server side.", ste);
+ + "Ignore in server side.");
return;
}
+ print("Server accepted connection");
// handle the connection
try {
@@ -353,6 +405,8 @@
sslSocket.close();
sslServerSocket.close();
}
+
+ test.signalServerDone();
}
/*
@@ -419,6 +473,8 @@
print("Run client application");
test.getClientApplication().run(sslSocket, test);
}
+
+ test.signalClientDone();
}
/*
--- a/jdk/test/sun/net/www/protocol/https/HttpsClient/OriginServer.java Thu Oct 20 18:35:45 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- *
- * This is a HTTP test server used by the regression test
- * for the bug fixes: 4323990, 4413069
- */
-
-import java.io.*;
-import java.net.*;
-import javax.net.*;
-
-/*
- * OriginServer.java -- a simple server that can serve
- * Http get request in both clear and secure channel
- */
-
-public abstract class OriginServer implements Runnable, Closeable {
-
- private ServerSocket server = null;
- Exception serverException = null;
- private volatile boolean closed;
-
- /**
- * Constructs a OriginServer based on ss and
- * obtains a response data's bytecodes using the method
- * getBytes.
- */
- protected OriginServer(ServerSocket ss) throws Exception
- {
- server = ss;
- newListener();
- if (serverException != null)
- throw serverException;
- }
-
- @Override
- public void close() throws IOException {
- if (closed)
- return;
- closed = true;
- server.close();
- }
-
- /**
- * Returns an array of bytes containing the bytes for
- * the data sent in the response.
- *
- * @return the bytes for the information that is being sent
- */
- public abstract byte[] getBytes();
-
- /**
- * The "listen" thread that accepts a connection to the
- * server, parses the header and sends back the response
- */
- public void run()
- {
- Socket socket;
-
- // accept a connection
- try {
- socket = server.accept();
- } catch (IOException e) {
- if (!closed) {
- System.out.println("Class Server died: " + e.getMessage());
- serverException = e;
- }
- return;
- }
- try {
- DataOutputStream out =
- new DataOutputStream(socket.getOutputStream());
- try {
- BufferedReader in =
- new BufferedReader(new InputStreamReader(
- socket.getInputStream()));
- // read the request
- readRequest(in);
- // retrieve bytecodes
- byte[] bytecodes = getBytes();
- // send bytecodes in response (assumes HTTP/1.0 or later)
- try {
- out.writeBytes("HTTP/1.0 200 OK\r\n");
- out.writeBytes("Content-Length: " + bytecodes.length +
- "\r\n");
- out.writeBytes("Content-Type: text/html\r\n\r\n");
- out.write(bytecodes);
- out.flush();
- } catch (IOException ie) {
- serverException = ie;
- return;
- }
-
- } catch (Exception e) {
- // write out error response
- out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
- out.writeBytes("Content-Type: text/html\r\n\r\n");
- out.flush();
- }
-
- } catch (IOException ex) {
- System.out.println("error writing response: " + ex.getMessage());
- serverException = ex;
-
- } finally {
- try {
- socket.close();
- } catch (IOException e) {
- serverException = e;
- }
- }
- }
-
- /**
- * Create a new thread to listen.
- */
- private void newListener()
- {
- (new Thread(this)).start();
- }
-
- /**
- * read the response, don't care for the syntax of the request-line
- * for this testing
- */
- private static void readRequest(BufferedReader in)
- throws IOException
- {
- String line = null;
- System.out.println("Server received: ");
- do {
- if (line != null)
- System.out.println(line);
- line = in.readLine();
- } while ((line.length() != 0) &&
- (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
- }
-}
--- a/jdk/test/sun/net/www/protocol/https/HttpsClient/ProxyAuthTest.java Thu Oct 20 18:35:45 2016 +0100
+++ b/jdk/test/sun/net/www/protocol/https/HttpsClient/ProxyAuthTest.java Thu Oct 20 11:23:41 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
* @summary HttpsURLConnection doesn't send Proxy-Authorization on CONNECT
* Incorrect checking of proxy server response
* @modules java.base/sun.net.www
+ * @library /javax/net/ssl/templates
* @run main/othervm ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic, ProxyAuthTest fail
@@ -41,12 +42,18 @@
// No way to reserve and restore java.lang.Authenticator, as well as read-once
// system properties, so this tests needs to run in othervm mode.
-import java.io.*;
-import java.net.*;
-import java.security.KeyStore;
-import javax.net.*;
-import javax.net.ssl.*;
-import java.security.cert.*;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.Authenticator;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.Proxy;
+import java.net.URL;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
import static java.nio.charset.StandardCharsets.US_ASCII;
/*
@@ -65,27 +72,20 @@
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
- volatile private static int serverPort = 0;
-
- /*
- * The TestServer implements a OriginServer that
- * processes HTTP requests and responses.
+ /**
+ * read the response, don't care for the syntax of the request-line
+ * for this testing
*/
- static class TestServer extends OriginServer {
- public TestServer(ServerSocket ss) throws Exception {
- super(ss);
- }
-
- /*
- * Returns an array of bytes containing the bytes for
- * the data sent in the response.
- *
- * @return bytes for the data in the response
- */
- public byte[] getBytes() {
- return "Proxy authentication for tunneling succeeded ..".
- getBytes(US_ASCII);
- }
+ private static void readRequest(BufferedReader in) throws IOException {
+ String line = null;
+ System.out.println("Server received: ");
+ do {
+ if (line != null) {
+ System.out.println(line);
+ }
+ line = in.readLine();
+ } while ((line.length() != 0) &&
+ (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
}
/*
@@ -93,94 +93,96 @@
*/
public static void main(String args[]) throws Exception {
boolean expectSuccess;
- if (args[0].equals("succeed")) {
- expectSuccess = true;
- } else {
- expectSuccess = false;
- }
+ expectSuccess = args[0].equals("succeed");
String keyFilename =
- System.getProperty("test.src", "./") + "/" + pathToStores +
- "/" + keyStoreFile;
+ SSLTest.TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
String trustFilename =
- System.getProperty("test.src", "./") + "/" + pathToStores +
- "/" + trustStoreFile;
+ SSLTest.TEST_SRC + "/" + pathToStores + "/" + trustStoreFile;
+
+ SSLTest.setup(keyFilename, trustFilename, passwd);
+
+ new SSLTest()
+ .setServerApplication((socket, test) -> {
+ DataOutputStream out = new DataOutputStream(
+ socket.getOutputStream());
- System.setProperty("javax.net.ssl.keyStore", keyFilename);
- System.setProperty("javax.net.ssl.keyStorePassword", passwd);
- System.setProperty("javax.net.ssl.trustStore", trustFilename);
- System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+ try {
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(socket.getInputStream()));
+
+ // read the request
+ readRequest(in);
+
+ // retrieve bytecodes
+ byte[] bytecodes =
+ "Proxy authentication for tunneling succeeded .."
+ .getBytes(US_ASCII);
- boolean useSSL = true;
- /*
- * setup the server
- */
- Closeable server;
- try {
- ServerSocketFactory ssf =
- ProxyAuthTest.getServerSocketFactory(useSSL);
- ServerSocket ss = ssf.createServerSocket(serverPort);
- serverPort = ss.getLocalPort();
- server = new TestServer(ss);
- } catch (Exception e) {
- System.out.println("Server side failed:" +
- e.getMessage());
- throw e;
- }
- // trigger the client
- try {
- doClientSide();
- if (!expectSuccess) {
- throw new RuntimeException(
- "Expected exception/failure to connect, but succeeded.");
- }
- } catch (IOException e) {
- if (expectSuccess) {
- System.out.println("Client side failed: " + e.getMessage());
- throw e;
- }
+ // send bytecodes in response (assumes HTTP/1.0 or later)
+ out.writeBytes("HTTP/1.0 200 OK\r\n");
+ out.writeBytes("Content-Length: " + bytecodes.length +
+ "\r\n");
+ out.writeBytes("Content-Type: text/html\r\n\r\n");
+ out.write(bytecodes);
+ out.flush();
+ } catch (IOException e) {
+ // write out error response
+ out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
+ out.writeBytes("Content-Type: text/html\r\n\r\n");
+ out.flush();
+ }
+ })
+ .setClientPeer(test -> {
+ try {
+ doClientSide(test);
+ if (!expectSuccess) {
+ throw new RuntimeException("Expected exception/failure "
+ + "to connect, but succeeded.");
+ }
+ } catch (IOException e) {
+ if (expectSuccess) {
+ System.out.println("Client side failed: "
+ + e.getMessage());
+ throw e;
+ }
- if (! (e.getMessage().contains("Unable to tunnel through proxy") &&
- e.getMessage().contains("407")) ) {
- throw new RuntimeException(
- "Expected exception about cannot tunnel, 407, etc, but got", e);
- } else {
- // Informative
- System.out.println("Caught expected exception: " + e.getMessage());
- }
- } finally {
- if (server != null)
- server.close();
- }
+ if (! (e.getMessage().contains(
+ "Unable to tunnel through proxy") &&
+ e.getMessage().contains("407")) ) {
+
+ throw new RuntimeException(
+ "Expected exception about cannot tunnel, "
+ + "407, etc, but got", e);
+ } else {
+ // Informative
+ System.out.println("Caught expected exception: "
+ + e.getMessage());
+ }
+ }
+ })
+ .runTest();
}
- private static ServerSocketFactory getServerSocketFactory
- (boolean useSSL) throws Exception {
- if (useSSL) {
- SSLServerSocketFactory ssf = null;
- // set up key manager to do server authentication
- SSLContext ctx;
- KeyManagerFactory kmf;
- KeyStore ks;
- char[] passphrase = passwd.toCharArray();
-
- ctx = SSLContext.getInstance("TLS");
- kmf = KeyManagerFactory.getInstance("SunX509");
- ks = KeyStore.getInstance("JKS");
+ static void doClientSide(SSLTest test) throws IOException {
- ks.load(new FileInputStream(System.getProperty(
- "javax.net.ssl.keyStore")), passphrase);
- kmf.init(ks, passphrase);
- ctx.init(kmf.getKeyManagers(), null, null);
+ // Wait for server to get started.
+ //
+ // The server side takes care of the issue if the server cannot
+ // get started in 90 seconds. The client side would just ignore
+ // the test case if the serer is not ready.
+ try {
+ if (!test.waitForServerSignal()) {
+ System.out.print("The server is not ready yet in 90 seconds. "
+ + "Ignore in client side.");
+ return;
+ }
+ } catch (InterruptedException e) {
+ System.out.print("InterruptedException occured. "
+ + "Ignore in client side.");
+ return;
+ }
- ssf = ctx.getServerSocketFactory();
- return ssf;
- } else {
- return ServerSocketFactory.getDefault();
- }
- }
-
- static void doClientSide() throws IOException {
/*
* setup up a proxy with authentication information
*/
@@ -190,23 +192,27 @@
* we want to avoid URLspoofCheck failures in cases where the cert
* DN name does not match the hostname in the URL.
*/
- HttpsURLConnection.setDefaultHostnameVerifier(
- new NameVerifier());
+ HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
- InetSocketAddress paddr = new InetSocketAddress("localhost", ps.getPort());
+ InetSocketAddress paddr = new InetSocketAddress(
+ "localhost", ps.getPort());
Proxy proxy = new Proxy(Proxy.Type.HTTP, paddr);
- URL url = new URL("https://" + "localhost:" + serverPort
- + "/index.html");
- BufferedReader in = null;
+ URL url = new URL("https://" + "localhost:" + test.getServerPort()
+ + "/index.html");
+
+ // Signal the server, the client is ready to communicate.
+ test.signalClientReady();
+
HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(proxy);
- try {
- in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
+ try (BufferedReader in = new BufferedReader(
+ new InputStreamReader(uc.getInputStream()))) {
+
String inputLine;
System.out.print("Client recieved from the server: ");
- while ((inputLine = in.readLine()) != null)
+ while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
- in.close();
+ }
} catch (IOException e) {
// Assert that the error stream is not accessible from the failed
// tunnel setup.
@@ -214,13 +220,13 @@
throw new RuntimeException("Unexpected error stream.");
}
- if (in != null)
- in.close();
throw e;
}
}
static class NameVerifier implements HostnameVerifier {
+
+ @Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
@@ -244,9 +250,9 @@
public static class TestAuthenticator extends Authenticator {
+ @Override
public PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication("Test",
- "test123".toCharArray());
+ return new PasswordAuthentication("Test", "test123".toCharArray());
}
}
}