src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/internal/websocket/OpeningHandshake.java
branchhttp-client-branch
changeset 55764 34d7cc00f87a
parent 47216 71c04702a3d5
child 55805 371ed971281e
equal deleted inserted replaced
55763:634d8e14c172 55764:34d7cc00f87a
    26 package jdk.incubator.http.internal.websocket;
    26 package jdk.incubator.http.internal.websocket;
    27 
    27 
    28 import jdk.incubator.http.internal.common.MinimalFuture;
    28 import jdk.incubator.http.internal.common.MinimalFuture;
    29 
    29 
    30 import java.io.IOException;
    30 import java.io.IOException;
       
    31 import java.net.Proxy;
    31 import java.net.URI;
    32 import java.net.URI;
    32 import java.net.URISyntaxException;
    33 import java.net.URISyntaxException;
    33 import jdk.incubator.http.HttpClient;
    34 import jdk.incubator.http.HttpClient;
    34 import jdk.incubator.http.HttpClient.Version;
    35 import jdk.incubator.http.HttpClient.Version;
    35 import jdk.incubator.http.HttpHeaders;
    36 import jdk.incubator.http.HttpHeaders;
    38 import jdk.incubator.http.HttpResponse.BodyHandler;
    39 import jdk.incubator.http.HttpResponse.BodyHandler;
    39 import jdk.incubator.http.WebSocketHandshakeException;
    40 import jdk.incubator.http.WebSocketHandshakeException;
    40 import jdk.incubator.http.internal.common.Pair;
    41 import jdk.incubator.http.internal.common.Pair;
    41 
    42 
    42 import java.nio.charset.StandardCharsets;
    43 import java.nio.charset.StandardCharsets;
       
    44 import java.security.AccessController;
    43 import java.security.MessageDigest;
    45 import java.security.MessageDigest;
    44 import java.security.NoSuchAlgorithmException;
    46 import java.security.NoSuchAlgorithmException;
       
    47 import java.security.PrivilegedAction;
    45 import java.security.SecureRandom;
    48 import java.security.SecureRandom;
    46 import java.time.Duration;
    49 import java.time.Duration;
    47 import java.util.Base64;
    50 import java.util.Base64;
    48 import java.util.Collection;
    51 import java.util.Collection;
    49 import java.util.Collections;
    52 import java.util.Collections;
    97 
   100 
    98     private final HttpRequest request;
   101     private final HttpRequest request;
    99     private final Collection<String> subprotocols;
   102     private final Collection<String> subprotocols;
   100     private final String nonce;
   103     private final String nonce;
   101 
   104 
   102     OpeningHandshake(BuilderImpl b) {
   105     OpeningHandshake(BuilderImpl b, Proxy proxy) {
   103         this.client = b.getClient();
   106         this.client = b.getClient();
   104         URI httpURI = createRequestURI(b.getUri());
   107         URI httpURI = createRequestURI(b.getUri());
   105         HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(httpURI);
   108         HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(httpURI);
   106         Duration connectTimeout = b.getConnectTimeout();
   109         Duration connectTimeout = b.getConnectTimeout();
   107         if (connectTimeout != null) {
   110         if (connectTimeout != null) {
   128         this.request = requestBuilder.version(Version.HTTP_1_1).GET().build();
   131         this.request = requestBuilder.version(Version.HTTP_1_1).GET().build();
   129         WebSocketRequest r = (WebSocketRequest) this.request;
   132         WebSocketRequest r = (WebSocketRequest) this.request;
   130         r.isWebSocket(true);
   133         r.isWebSocket(true);
   131         r.setSystemHeader(HEADER_UPGRADE, "websocket");
   134         r.setSystemHeader(HEADER_UPGRADE, "websocket");
   132         r.setSystemHeader(HEADER_CONNECTION, "Upgrade");
   135         r.setSystemHeader(HEADER_CONNECTION, "Upgrade");
       
   136         r.setProxy(proxy);
   133     }
   137     }
   134 
   138 
   135     private static Collection<String> createRequestSubprotocols(
   139     private static Collection<String> createRequestSubprotocols(
   136             Collection<String> subprotocols)
   140             Collection<String> subprotocols)
   137     {
   141     {
   151      * Checks the given URI for being a WebSocket URI and translates it into a
   155      * Checks the given URI for being a WebSocket URI and translates it into a
   152      * target HTTP URI for the Opening Handshake.
   156      * target HTTP URI for the Opening Handshake.
   153      *
   157      *
   154      * https://tools.ietf.org/html/rfc6455#section-3
   158      * https://tools.ietf.org/html/rfc6455#section-3
   155      */
   159      */
   156     private static URI createRequestURI(URI uri) {
   160     static URI createRequestURI(URI uri) {
   157         // TODO: check permission for WebSocket URI and translate it into
       
   158         // http/https permission
       
   159         String s = uri.getScheme(); // The scheme might be null (i.e. undefined)
   161         String s = uri.getScheme(); // The scheme might be null (i.e. undefined)
   160         if (!("ws".equalsIgnoreCase(s) || "wss".equalsIgnoreCase(s))
   162         if (!("ws".equalsIgnoreCase(s) || "wss".equalsIgnoreCase(s))
   161                 || uri.getFragment() != null)
   163                 || uri.getFragment() != null)
   162         {
   164         {
   163             throw illegal("Bad URI: " + uri);
   165             throw illegal("Bad URI: " + uri);
   176             throw new InternalError(e);
   178             throw new InternalError(e);
   177         }
   179         }
   178     }
   180     }
   179 
   181 
   180     CompletableFuture<Result> send() {
   182     CompletableFuture<Result> send() {
   181         return client.sendAsync(this.request, BodyHandler.<Void>discard(null))
   183         PrivilegedAction<CompletableFuture<Result>> pa = () ->
   182                 .thenCompose(this::resultFrom);
   184                 client.sendAsync(this.request, BodyHandler.<Void>discard(null))
       
   185                       .thenCompose(this::resultFrom);
       
   186         return AccessController.doPrivileged(pa);
   183     }
   187     }
   184 
   188 
   185     /*
   189     /*
   186      * The result of the opening handshake.
   190      * The result of the opening handshake.
   187      */
   191      */
   245         String x = this.nonce + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
   249         String x = this.nonce + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
   246         this.sha1.update(x.getBytes(StandardCharsets.ISO_8859_1));
   250         this.sha1.update(x.getBytes(StandardCharsets.ISO_8859_1));
   247         String expected = Base64.getEncoder().encodeToString(this.sha1.digest());
   251         String expected = Base64.getEncoder().encodeToString(this.sha1.digest());
   248         String actual = requireSingle(headers, HEADER_ACCEPT);
   252         String actual = requireSingle(headers, HEADER_ACCEPT);
   249         if (!actual.trim().equals(expected)) {
   253         if (!actual.trim().equals(expected)) {
   250             throw checkFailed("Bad " + HEADER_ACCEPT);
   254             throw checkFailed("Bad " + HEADER_ACCEPT + ", expected:["
       
   255                               + expected + "] ,got:[" + actual.trim() + "]");
   251         }
   256         }
   252         String subprotocol = checkAndReturnSubprotocol(headers);
   257         String subprotocol = checkAndReturnSubprotocol(headers);
   253         RawChannel channel = ((RawChannel.Provider) response).rawChannel();
   258         RawChannel channel = ((RawChannel.Provider) response).rawChannel();
   254         return new Result(subprotocol, channel);
   259         return new Result(subprotocol, channel);
   255     }
   260     }