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 ---