test/jdk/java/net/httpclient/HandshakeFailureTest.java
branchhttp-client-branch
changeset 55763 634d8e14c172
child 49765 ee6f7a61f3a5
child 56082 1da51fab3032
equal deleted inserted replaced
55762:e947a3a50a95 55763:634d8e14c172
       
     1 /*
       
     2  * Copyright (c) 2017, 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 import javax.net.ServerSocketFactory;
       
    25 import javax.net.ssl.SSLContext;
       
    26 import javax.net.ssl.SSLHandshakeException;
       
    27 import javax.net.ssl.SSLSocket;
       
    28 import java.io.DataInputStream;
       
    29 import java.io.IOException;
       
    30 import java.io.UncheckedIOException;
       
    31 import java.net.ServerSocket;
       
    32 import java.net.Socket;
       
    33 import java.net.URI;
       
    34 import java.util.List;
       
    35 import java.util.concurrent.CompletableFuture;
       
    36 import java.util.concurrent.CompletionException;
       
    37 import jdk.incubator.http.HttpClient;
       
    38 import jdk.incubator.http.HttpClient.Version;
       
    39 import jdk.incubator.http.HttpResponse;
       
    40 import jdk.incubator.http.HttpRequest;
       
    41 import static java.lang.System.out;
       
    42 import static jdk.incubator.http.HttpResponse.BodyHandler.discard;
       
    43 
       
    44 /**
       
    45  * @test
       
    46  * @run main/othervm HandshakeFailureTest
       
    47  * @summary Verify SSLHandshakeException is received when the handshake fails,
       
    48  * either because the server closes ( EOF ) the connection during handshaking
       
    49  * or no cipher suite ( or similar ) can be negotiated.
       
    50  */
       
    51 // To switch on debugging use:
       
    52 // @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest
       
    53 public class HandshakeFailureTest {
       
    54 
       
    55     // The number of iterations each testXXXClient performs. Can be increased
       
    56     // when running standalone testing.
       
    57     static final int TIMES = 10;
       
    58 
       
    59     public static void main(String[] args) throws Exception {
       
    60         HandshakeFailureTest test = new HandshakeFailureTest();
       
    61         List<AbstractServer> servers = List.of( new PlainServer(), new SSLServer());
       
    62 
       
    63         for (AbstractServer server : servers) {
       
    64             try (server) {
       
    65                 out.format("%n%n------ Testing with server:%s ------%n", server);
       
    66                 URI uri = new URI("https://127.0.0.1:" + server.getPort() + "/");
       
    67 
       
    68                 test.testSyncSameClient(uri, Version.HTTP_1_1);
       
    69                 test.testSyncSameClient(uri, Version.HTTP_2);
       
    70                 test.testSyncDiffClient(uri, Version.HTTP_1_1);
       
    71                 test.testSyncDiffClient(uri, Version.HTTP_2);
       
    72 
       
    73                 test.testAsyncSameClient(uri, Version.HTTP_1_1);
       
    74                 test.testAsyncSameClient(uri, Version.HTTP_2);
       
    75                 test.testAsyncDiffClient(uri, Version.HTTP_1_1);
       
    76                 test.testAsyncDiffClient(uri, Version.HTTP_2);
       
    77             }
       
    78         }
       
    79     }
       
    80 
       
    81     void testSyncSameClient(URI uri, Version version) throws Exception {
       
    82         out.printf("%n--- testSyncSameClient %s ---%n", version);
       
    83         HttpClient client = HttpClient.newHttpClient();
       
    84         for (int i = 0; i < TIMES; i++) {
       
    85             out.printf("iteration %d%n", i);
       
    86             HttpRequest request = HttpRequest.newBuilder(uri)
       
    87                                              .version(version)
       
    88                                              .build();
       
    89             try {
       
    90                 HttpResponse<Void> response = client.send(request, discard(null));
       
    91                 String msg = String.format("UNEXPECTED response=%s%n", response);
       
    92                 throw new RuntimeException(msg);
       
    93             } catch (SSLHandshakeException expected) {
       
    94                 out.printf("Client: caught expected exception: %s%n", expected);
       
    95             }
       
    96         }
       
    97     }
       
    98 
       
    99     void testSyncDiffClient(URI uri, Version version) throws Exception {
       
   100         out.printf("%n--- testSyncDiffClient %s ---%n", version);
       
   101         for (int i = 0; i < TIMES; i++) {
       
   102             out.printf("iteration %d%n", i);
       
   103             // a new client each time
       
   104             HttpClient client = HttpClient.newHttpClient();
       
   105             HttpRequest request = HttpRequest.newBuilder(uri)
       
   106                                              .version(version)
       
   107                                              .build();
       
   108             try {
       
   109                 HttpResponse<Void> response = client.send(request, discard(null));
       
   110                 String msg = String.format("UNEXPECTED response=%s%n", response);
       
   111                 throw new RuntimeException(msg);
       
   112             } catch (SSLHandshakeException expected) {
       
   113                 out.printf("Client: caught expected exception: %s%n", expected);
       
   114             }
       
   115         }
       
   116     }
       
   117 
       
   118     void testAsyncSameClient(URI uri, Version version) throws Exception {
       
   119         out.printf("%n--- testAsyncSameClient %s ---%n", version);
       
   120         HttpClient client = HttpClient.newHttpClient();
       
   121         for (int i = 0; i < TIMES; i++) {
       
   122             out.printf("iteration %d%n", i);
       
   123             HttpRequest request = HttpRequest.newBuilder(uri)
       
   124                                              .version(version)
       
   125                                              .build();
       
   126             CompletableFuture<HttpResponse<Void>> response =
       
   127                         client.sendAsync(request, discard(null));
       
   128             try {
       
   129                 response.join();
       
   130                 String msg = String.format("UNEXPECTED response=%s%n", response);
       
   131                 throw new RuntimeException(msg);
       
   132             } catch (CompletionException ce) {
       
   133                 if (ce.getCause() instanceof SSLHandshakeException) {
       
   134                     out.printf("Client: caught expected exception: %s%n", ce.getCause());
       
   135                 } else {
       
   136                     out.printf("Client: caught UNEXPECTED exception: %s%n", ce.getCause());
       
   137                     throw ce;
       
   138                 }
       
   139             }
       
   140         }
       
   141     }
       
   142 
       
   143     void testAsyncDiffClient(URI uri, Version version) throws Exception {
       
   144         out.printf("%n--- testAsyncDiffClient %s ---%n", version);
       
   145         for (int i = 0; i < TIMES; i++) {
       
   146             out.printf("iteration %d%n", i);
       
   147             // a new client each time
       
   148             HttpClient client = HttpClient.newHttpClient();
       
   149             HttpRequest request = HttpRequest.newBuilder(uri)
       
   150                                              .version(version)
       
   151                                              .build();
       
   152             CompletableFuture<HttpResponse<Void>> response =
       
   153                     client.sendAsync(request, discard(null));
       
   154             try {
       
   155                 response.join();
       
   156                 String msg = String.format("UNEXPECTED response=%s%n", response);
       
   157                 throw new RuntimeException(msg);
       
   158             } catch (CompletionException ce) {
       
   159                 if (ce.getCause() instanceof SSLHandshakeException) {
       
   160                     out.printf("Client: caught expected exception: %s%n", ce.getCause());
       
   161                 } else {
       
   162                     out.printf("Client: caught UNEXPECTED exception: %s%n", ce.getCause());
       
   163                     throw ce;
       
   164                 }
       
   165             }
       
   166         }
       
   167     }
       
   168 
       
   169     /** Common supertype for PlainServer and SSLServer. */
       
   170     static abstract class AbstractServer extends Thread implements AutoCloseable {
       
   171         protected final ServerSocket ss;
       
   172         protected volatile boolean closed;
       
   173 
       
   174         AbstractServer(String name, ServerSocket ss) throws IOException {
       
   175             super(name);
       
   176             this.ss = ss;
       
   177             this.start();
       
   178         }
       
   179 
       
   180         int getPort() { return ss.getLocalPort(); }
       
   181 
       
   182         @Override
       
   183         public void close() {
       
   184             if (closed)
       
   185                 return;
       
   186             closed = true;
       
   187             try {
       
   188                 ss.close();
       
   189             } catch (IOException e) {
       
   190                 throw new UncheckedIOException("Unexpected", e);
       
   191             }
       
   192         }
       
   193     }
       
   194 
       
   195     /** Emulates a server-side, using plain cleartext Sockets, that just closes
       
   196      * the connection, after a small variable delay. */
       
   197     static class PlainServer extends AbstractServer {
       
   198         private volatile int count;
       
   199 
       
   200         PlainServer() throws IOException {
       
   201             super("PlainServer", new ServerSocket(0));
       
   202         }
       
   203 
       
   204         @Override
       
   205         public void run() {
       
   206             while (!closed) {
       
   207                 try (Socket s = ss.accept()) {
       
   208                     count++;
       
   209 
       
   210                     /*   SSL record layer - contains the client hello
       
   211                     struct {
       
   212                         uint8 major, minor;
       
   213                     } ProtocolVersion;
       
   214 
       
   215                     enum {
       
   216                         change_cipher_spec(20), alert(21), handshake(22),
       
   217                         application_data(23), (255)
       
   218                     } ContentType;
       
   219 
       
   220                     struct {
       
   221                         ContentType type;
       
   222                         ProtocolVersion version;
       
   223                         uint16 length;
       
   224                         opaque fragment[SSLPlaintext.length];
       
   225                     } SSLPlaintext;   */
       
   226                     DataInputStream din =  new DataInputStream(s.getInputStream());
       
   227                     int contentType = din.read();
       
   228                     out.println("ContentType:" + contentType);
       
   229                     int majorVersion = din.read();
       
   230                     out.println("Major:" + majorVersion);
       
   231                     int minorVersion = din.read();
       
   232                     out.println("Minor:" + minorVersion);
       
   233                     int length = din.readShort();
       
   234                     out.println("length:" + length);
       
   235                     byte[] ba = new byte[length];
       
   236                     din.readFully(ba);
       
   237 
       
   238                     // simulate various delays in response
       
   239                     Thread.sleep(10 * (count % 10));
       
   240                     s.close(); // close without giving any reply
       
   241                 } catch (IOException e) {
       
   242                     if (!closed)
       
   243                         out.println("Unexpected" + e);
       
   244                 } catch (InterruptedException e) {
       
   245                     throw new RuntimeException(e);
       
   246                 }
       
   247             }
       
   248         }
       
   249     }
       
   250 
       
   251     /** Emulates a server-side, using SSL Sockets, that will fail during
       
   252      * handshaking, as there are no cipher suites in common. */
       
   253     static class SSLServer extends AbstractServer {
       
   254         static final SSLContext sslContext = createUntrustingContext();
       
   255         static final ServerSocketFactory factory = sslContext.getServerSocketFactory();
       
   256 
       
   257         static SSLContext createUntrustingContext() {
       
   258             try {
       
   259                 SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
       
   260                 sslContext.init(null, null, null);
       
   261                 return sslContext;
       
   262             } catch (Throwable t) {
       
   263                 throw new AssertionError(t);
       
   264             }
       
   265         }
       
   266 
       
   267         SSLServer() throws IOException {
       
   268             super("SSLServer", factory.createServerSocket(0));
       
   269         }
       
   270 
       
   271         @Override
       
   272         public void run() {
       
   273             while (!closed) {
       
   274                 try (SSLSocket s = (SSLSocket)ss.accept()) {
       
   275                     s.getInputStream().read();  // will throw SHE here
       
   276 
       
   277                     throw new AssertionError("Should not reach here");
       
   278                 } catch (SSLHandshakeException expected) {
       
   279                     // Expected: SSLHandshakeException: no cipher suites in common
       
   280                     out.printf("Server: caught expected exception: %s%n", expected);
       
   281                 } catch (IOException e) {
       
   282                     if (!closed)
       
   283                         out.printf("UNEXPECTED %s", e);
       
   284                 }
       
   285             }
       
   286         }
       
   287     }
       
   288 }