1 /* 2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 4474255 27 * @summary Can no longer obtain a com.sun.net.ssl.HttpsURLConnection 28 * @run main/othervm ComHTTPSConnection 29 * 30 * SunJSSE does not support dynamic system properties, no way to re-use 31 * system properties in samevm/agentvm mode. 32 * @author Brad Wetmore 33 */ 34 35 import java.io.*; 36 import java.net.*; 37 import javax.net.ssl.*; 38 import javax.security.cert.*; 39 import com.sun.net.ssl.HostnameVerifier; 40 import com.sun.net.ssl.HttpsURLConnection; 41 42 /** 43 * See if we can obtain a com.sun.net.ssl.HttpsURLConnection, 44 * and then play with it a bit. 45 */ 46 public class ComHTTPSConnection { 47 48 /* 49 * ============================================================= 50 * Set the various variables needed for the tests, then 51 * specify what tests to run on each side. 52 */ 53 54 /* 55 * Should we run the client or server in a separate thread? 56 * Both sides can throw exceptions, but do you have a preference 57 * as to which side should be the main thread. 58 */ 59 static boolean separateServerThread = true; 60 61 /* 62 * Where do we find the keystores? 63 */ 64 static String pathToStores = "../../../../../../javax/net/ssl/etc"; 65 static String keyStoreFile = "keystore"; 66 static String trustStoreFile = "truststore"; 67 static String passwd = "passphrase"; 68 69 /* 70 * Is the server ready to serve? 71 */ 72 volatile static boolean serverReady = false; 73 74 /* 75 * Turn on SSL debugging? 76 */ 77 static boolean debug = false; 78 79 /* 80 * If the client or server is doing some kind of object creation 81 * that the other side depends on, and that thread prematurely 82 * exits, you may experience a hang. The test harness will 83 * terminate all hung threads after its timeout has expired, 84 * currently 3 minutes by default, but you might try to be 85 * smart about it.... 86 */ 87 88 /** 89 * Returns the path to the file obtained from 90 * parsing the HTML header. 91 */ 92 private static String getPath(DataInputStream in) 93 throws IOException 94 { 95 String line = in.readLine(); 96 String path = ""; 97 // extract class from GET line 98 if (line.startsWith("GET /")) { 99 line = line.substring(5, line.length()-1).trim(); 100 int index = line.indexOf(' '); 101 if (index != -1) { 102 path = line.substring(0, index); 103 } 104 } 105 106 // eat the rest of header 107 do { 108 line = in.readLine(); 109 } while ((line.length() != 0) && 110 (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); 111 112 if (path.length() != 0) { 113 return path; 114 } else { 115 throw new IOException("Malformed Header"); 116 } 117 } 118 119 /** 120 * Returns an array of bytes containing the bytes for 121 * the file represented by the argument <b>path</b>. 122 * 123 * In our case, we just pretend to send something back. 124 * 125 * @return the bytes for the file 126 * @exception FileNotFoundException if the file corresponding 127 * to <b>path</b> could not be loaded. 128 */ 129 private byte[] getBytes(String path) 130 throws IOException 131 { 132 return "Hello world, I am here".getBytes(); 133 } 134 135 /* 136 * Define the server side of the test. 137 * 138 * If the server prematurely exits, serverReady will be set to true 139 * to avoid infinite hangs. 140 */ 141 void doServerSide() throws Exception { 142 143 SSLServerSocketFactory sslssf = 144 (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 145 SSLServerSocket sslServerSocket = 146 (SSLServerSocket) sslssf.createServerSocket(serverPort); 147 serverPort = sslServerSocket.getLocalPort(); 148 149 /* 150 * Signal Client, we're ready for his connect. 151 */ 152 serverReady = true; 153 154 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 155 DataOutputStream out = 156 new DataOutputStream(sslSocket.getOutputStream()); 157 158 try { 159 // get path to class file from header 160 DataInputStream in = 161 new DataInputStream(sslSocket.getInputStream()); 162 String path = getPath(in); 163 // retrieve bytecodes 164 byte[] bytecodes = getBytes(path); 165 // send bytecodes in response (assumes HTTP/1.0 or later) 166 try { 167 out.writeBytes("HTTP/1.0 200 OK\r\n"); 168 out.writeBytes("Content-Length: " + bytecodes.length + "\r\n"); 169 out.writeBytes("Content-Type: text/html\r\n\r\n"); 170 out.write(bytecodes); 171 out.flush(); 172 } catch (IOException ie) { 173 ie.printStackTrace(); 174 return; 175 } 176 177 } catch (Exception e) { 178 e.printStackTrace(); 179 // write out error response 180 out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n"); 181 out.writeBytes("Content-Type: text/html\r\n\r\n"); 182 out.flush(); 183 } finally { 184 // close the socket 185 System.out.println("Server closing socket"); 186 sslSocket.close(); 187 serverReady = false; 188 } 189 } 190 191 /* 192 * Define the client side of the test. 193 * 194 * If the server prematurely exits, serverReady will be set to true 195 * to avoid infinite hangs. 196 */ 197 void doClientSide() throws Exception { 198 /* 199 * Wait for server to get started. 200 */ 201 while (!serverReady) { 202 Thread.sleep(50); 203 } 204 205 HostnameVerifier reservedHV = 206 HttpsURLConnection.getDefaultHostnameVerifier(); 207 try { 208 System.setProperty("java.protocol.handler.pkgs", 209 "com.sun.net.ssl.internal.www.protocol"); 210 HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier()); 211 212 URL url = new URL("https://" + "localhost:" + serverPort + 213 "/etc/hosts"); 214 URLConnection urlc = url.openConnection(); 215 216 if (!(urlc instanceof com.sun.net.ssl.HttpsURLConnection)) { 217 throw new Exception( 218 "URLConnection ! instanceof " + 219 "com.sun.net.ssl.HttpsURLConnection"); 220 } 221 222 BufferedReader in = null; 223 try { 224 in = new BufferedReader(new InputStreamReader( 225 urlc.getInputStream())); 226 String inputLine; 227 System.out.print("Client reading... "); 228 while ((inputLine = in.readLine()) != null) 229 System.out.println(inputLine); 230 231 System.out.println("Cipher Suite: " + 232 ((HttpsURLConnection)urlc).getCipherSuite()); 233 X509Certificate[] certs = 234 ((HttpsURLConnection)urlc).getServerCertificateChain(); 235 for (int i = 0; i < certs.length; i++) { 236 System.out.println(certs[0]); 237 } 238 239 in.close(); 240 } catch (SSLException e) { 241 if (in != null) 242 in.close(); 243 throw e; 244 } 245 System.out.println("Client reports: SUCCESS"); 246 } finally { 247 HttpsURLConnection.setDefaultHostnameVerifier(reservedHV); 248 } 249 } 250 251 static class NameVerifier implements HostnameVerifier { 252 public boolean verify(String urlHostname, 253 String certHostname) { 254 System.out.println( 255 "CertificateHostnameVerifier: " + urlHostname + " == " 256 + certHostname + " returning true"); 257 return true; 258 } 259 } 260 261 /* 262 * ============================================================= 263 * The remainder is just support stuff 264 */ 265 266 // use any free port by default 267 volatile int serverPort = 0; 268 269 volatile Exception serverException = null; 270 volatile Exception clientException = null; 271 272 public static void main(String[] args) throws Exception { 273 String keyFilename = 274 System.getProperty("test.src", "./") + "/" + pathToStores + 275 "/" + keyStoreFile; 276 String trustFilename = 277 System.getProperty("test.src", "./") + "/" + pathToStores + 278 "/" + trustStoreFile; 279 280 System.setProperty("javax.net.ssl.keyStore", keyFilename); 281 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 282 System.setProperty("javax.net.ssl.trustStore", trustFilename); 283 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 284 285 if (debug) 286 System.setProperty("javax.net.debug", "all"); 287 288 /* 289 * Start the tests. 290 */ 291 new ComHTTPSConnection(); 292 } 293 294 Thread clientThread = null; 295 Thread serverThread = null; 296 297 /* 298 * Primary constructor, used to drive remainder of the test. 299 * 300 * Fork off the other side, then do your work. 301 */ 302 ComHTTPSConnection() throws Exception { 303 if (separateServerThread) { 304 startServer(true); 305 startClient(false); 306 } else { 307 startClient(true); 308 startServer(false); 309 } 310 311 /* 312 * Wait for other side to close down. 313 */ 314 if (separateServerThread) { 315 serverThread.join(); 316 } else { 317 clientThread.join(); 318 } 319 320 /* 321 * When we get here, the test is pretty much over. 322 * 323 * If the main thread excepted, that propagates back 324 * immediately. If the other thread threw an exception, we 325 * should report back. 326 */ 327 if (serverException != null) { 328 System.out.print("Server Exception:"); 329 throw serverException; 330 } 331 if (clientException != null) { 332 System.out.print("Client Exception:"); 333 throw clientException; 334 } 335 } 336 337 void startServer(boolean newThread) throws Exception { 338 if (newThread) { 339 serverThread = new Thread() { 340 public void run() { 341 try { 342 doServerSide(); 343 } catch (Exception e) { 344 /* 345 * Our server thread just died. 346 * 347 * Release the client, if not active already... 348 */ 349 System.err.println("Server died..."); 350 serverReady = true; 351 serverException = e; 352 } 353 } 354 }; 355 serverThread.start(); 356 } else { 357 doServerSide(); 358 } 359 } 360 361 void startClient(boolean newThread) throws Exception { 362 if (newThread) { 363 clientThread = new Thread() { 364 public void run() { 365 try { 366 doClientSide(); 367 } catch (Exception e) { 368 /* 369 * Our client thread just died. 370 */ 371 System.err.println("Client died..."); 372 clientException = e; 373 } 374 } 375 }; 376 clientThread.start(); 377 } else { 378 doClientSide(); 379 } 380 } 381 }