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 private static class ComSunHTTPSHandlerFactory implements URLStreamHandlerFactory { 192 private static String SUPPORTED_PROTOCOL = "https"; 193 194 public URLStreamHandler createURLStreamHandler(String protocol) { 195 if (!protocol.equalsIgnoreCase(SUPPORTED_PROTOCOL)) 196 return null; 197 198 return new com.sun.net.ssl.internal.www.protocol.https.Handler(); 199 } 200 } 201 202 /* 203 * Define the client side of the test. 204 * 205 * If the server prematurely exits, serverReady will be set to true 206 * to avoid infinite hangs. 207 */ 208 void doClientSide() throws Exception { 209 /* 210 * Wait for server to get started. 211 */ 212 while (!serverReady) { 213 Thread.sleep(50); 214 } 215 216 HostnameVerifier reservedHV = 217 HttpsURLConnection.getDefaultHostnameVerifier(); 218 try { 219 URL.addURLStreamHandlerFactory(new ComSunHTTPSHandlerFactory()); 220 HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier()); 221 222 URL url = new URL("https://" + "localhost:" + serverPort + 223 "/etc/hosts"); 224 URLConnection urlc = url.openConnection(); 225 226 if (!(urlc instanceof com.sun.net.ssl.HttpsURLConnection)) { 227 throw new Exception( 228 "URLConnection ! instanceof " + 229 "com.sun.net.ssl.HttpsURLConnection"); 230 } 231 232 BufferedReader in = null; 233 try { 234 in = new BufferedReader(new InputStreamReader( 235 urlc.getInputStream())); 236 String inputLine; 237 System.out.print("Client reading... "); 238 while ((inputLine = in.readLine()) != null) 239 System.out.println(inputLine); 240 241 System.out.println("Cipher Suite: " + 242 ((HttpsURLConnection)urlc).getCipherSuite()); 243 X509Certificate[] certs = 244 ((HttpsURLConnection)urlc).getServerCertificateChain(); 245 for (int i = 0; i < certs.length; i++) { 246 System.out.println(certs[0]); 247 } 248 249 in.close(); 250 } catch (SSLException e) { 251 if (in != null) 252 in.close(); 253 throw e; 254 } 255 System.out.println("Client reports: SUCCESS"); 256 } finally { 257 HttpsURLConnection.setDefaultHostnameVerifier(reservedHV); 258 } 259 } 260 261 static class NameVerifier implements HostnameVerifier { 262 public boolean verify(String urlHostname, 263 String certHostname) { 264 System.out.println( 265 "CertificateHostnameVerifier: " + urlHostname + " == " 266 + certHostname + " returning true"); 267 return true; 268 } 269 } 270 271 /* 272 * ============================================================= 273 * The remainder is just support stuff 274 */ 275 276 // use any free port by default 277 volatile int serverPort = 0; 278 279 volatile Exception serverException = null; 280 volatile Exception clientException = null; 281 282 public static void main(String[] args) throws Exception { 283 String keyFilename = 284 System.getProperty("test.src", "./") + "/" + pathToStores + 285 "/" + keyStoreFile; 286 String trustFilename = 287 System.getProperty("test.src", "./") + "/" + pathToStores + 288 "/" + trustStoreFile; 289 290 System.setProperty("javax.net.ssl.keyStore", keyFilename); 291 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 292 System.setProperty("javax.net.ssl.trustStore", trustFilename); 293 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 294 295 if (debug) 296 System.setProperty("javax.net.debug", "all"); 297 298 /* 299 * Start the tests. 300 */ 301 new ComHTTPSConnection(); 302 } 303 304 Thread clientThread = null; 305 Thread serverThread = null; 306 307 /* 308 * Primary constructor, used to drive remainder of the test. 309 * 310 * Fork off the other side, then do your work. 311 */ 312 ComHTTPSConnection() throws Exception { 313 if (separateServerThread) { 314 startServer(true); 315 startClient(false); 316 } else { 317 startClient(true); 318 startServer(false); 319 } 320 321 /* 322 * Wait for other side to close down. 323 */ 324 if (separateServerThread) { 325 serverThread.join(); 326 } else { 327 clientThread.join(); 328 } 329 330 /* 331 * When we get here, the test is pretty much over. 332 * 333 * If the main thread excepted, that propagates back 334 * immediately. If the other thread threw an exception, we 335 * should report back. 336 */ 337 if (serverException != null) { 338 System.out.print("Server Exception:"); 339 throw serverException; 340 } 341 if (clientException != null) { 342 System.out.print("Client Exception:"); 343 throw clientException; 344 } 345 } 346 347 void startServer(boolean newThread) throws Exception { 348 if (newThread) { 349 serverThread = new Thread() { 350 public void run() { 351 try { 352 doServerSide(); 353 } catch (Exception e) { 354 /* 355 * Our server thread just died. 356 * 357 * Release the client, if not active already... 358 */ 359 System.err.println("Server died..."); 360 serverReady = true; 361 serverException = e; 362 } 363 } 364 }; 365 serverThread.start(); 366 } else { 367 doServerSide(); 368 } 369 } 370 371 void startClient(boolean newThread) throws Exception { 372 if (newThread) { 373 clientThread = new Thread() { 374 public void run() { 375 try { 376 doClientSide(); 377 } catch (Exception e) { 378 /* 379 * Our client thread just died. 380 */ 381 System.err.println("Client died..."); 382 clientException = e; 383 } 384 } 385 }; 386 clientThread.start(); 387 } else { 388 doClientSide(); 389 } 390 } 391 } --- EOF ---