src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/internal/websocket/WebSocketImpl.java
branchhttp-client-branch
changeset 55764 34d7cc00f87a
parent 55763 634d8e14c172
child 55768 8674257c75ce
equal deleted inserted replaced
55763:634d8e14c172 55764:34d7cc00f87a
    24  */
    24  */
    25 
    25 
    26 package jdk.incubator.http.internal.websocket;
    26 package jdk.incubator.http.internal.websocket;
    27 
    27 
    28 import java.io.IOException;
    28 import java.io.IOException;
       
    29 import java.net.InetSocketAddress;
    29 import java.net.ProtocolException;
    30 import java.net.ProtocolException;
       
    31 import java.net.Proxy;
       
    32 import java.net.ProxySelector;
    30 import java.net.URI;
    33 import java.net.URI;
       
    34 import java.net.URISyntaxException;
       
    35 import java.net.URLPermission;
    31 import java.nio.ByteBuffer;
    36 import java.nio.ByteBuffer;
       
    37 import java.util.Collection;
       
    38 import java.util.List;
       
    39 import java.util.Optional;
    32 import java.util.Queue;
    40 import java.util.Queue;
    33 import java.util.concurrent.CompletableFuture;
    41 import java.util.concurrent.CompletableFuture;
    34 import java.util.concurrent.CompletionStage;
    42 import java.util.concurrent.CompletionStage;
    35 import java.util.concurrent.ConcurrentLinkedQueue;
    43 import java.util.concurrent.ConcurrentLinkedQueue;
    36 import java.util.concurrent.atomic.AtomicBoolean;
    44 import java.util.concurrent.atomic.AtomicBoolean;
    37 import java.util.function.Consumer;
    45 import java.util.function.Consumer;
    38 import java.util.function.Function;
    46 import java.util.function.Function;
       
    47 
       
    48 import jdk.incubator.http.HttpClient;
    39 import jdk.incubator.http.WebSocket;
    49 import jdk.incubator.http.WebSocket;
    40 import jdk.incubator.http.internal.common.Log;
    50 import jdk.incubator.http.internal.common.Log;
    41 import jdk.incubator.http.internal.common.Pair;
    51 import jdk.incubator.http.internal.common.Pair;
    42 import jdk.incubator.http.internal.common.SequentialScheduler;
    52 import jdk.incubator.http.internal.common.SequentialScheduler;
    43 import jdk.incubator.http.internal.common.SequentialScheduler.DeferredCompleter;
    53 import jdk.incubator.http.internal.common.SequentialScheduler.DeferredCompleter;
       
    54 import jdk.incubator.http.internal.common.Utils;
    44 import jdk.incubator.http.internal.websocket.OpeningHandshake.Result;
    55 import jdk.incubator.http.internal.websocket.OpeningHandshake.Result;
    45 import jdk.incubator.http.internal.websocket.OutgoingMessage.Binary;
    56 import jdk.incubator.http.internal.websocket.OutgoingMessage.Binary;
    46 import jdk.incubator.http.internal.websocket.OutgoingMessage.Close;
    57 import jdk.incubator.http.internal.websocket.OutgoingMessage.Close;
    47 import jdk.incubator.http.internal.websocket.OutgoingMessage.Context;
    58 import jdk.incubator.http.internal.websocket.OutgoingMessage.Context;
    48 import jdk.incubator.http.internal.websocket.OutgoingMessage.Ping;
    59 import jdk.incubator.http.internal.websocket.OutgoingMessage.Ping;
    49 import jdk.incubator.http.internal.websocket.OutgoingMessage.Pong;
    60 import jdk.incubator.http.internal.websocket.OutgoingMessage.Pong;
    50 import jdk.incubator.http.internal.websocket.OutgoingMessage.Text;
    61 import jdk.incubator.http.internal.websocket.OutgoingMessage.Text;
    51 
    62 
    52 import static java.util.Objects.requireNonNull;
    63 import static java.util.Objects.requireNonNull;
    53 import static java.util.concurrent.CompletableFuture.failedFuture;
    64 import static java.util.concurrent.CompletableFuture.failedFuture;
       
    65 import static java.util.stream.Collectors.joining;
    54 import static jdk.incubator.http.internal.common.Pair.pair;
    66 import static jdk.incubator.http.internal.common.Pair.pair;
    55 import jdk.incubator.http.internal.common.Utils;
       
    56 import static jdk.incubator.http.internal.websocket.StatusCodes.CLOSED_ABNORMALLY;
    67 import static jdk.incubator.http.internal.websocket.StatusCodes.CLOSED_ABNORMALLY;
    57 import static jdk.incubator.http.internal.websocket.StatusCodes.NO_STATUS_CODE;
    68 import static jdk.incubator.http.internal.websocket.StatusCodes.NO_STATUS_CODE;
    58 import static jdk.incubator.http.internal.websocket.StatusCodes.isLegalToSendFromClient;
    69 import static jdk.incubator.http.internal.websocket.StatusCodes.isLegalToSendFromClient;
    59 
    70 
    60 /*
    71 /*
   103     private final Object lock = new Object();
   114     private final Object lock = new Object();
   104 
   115 
   105     private final CompletableFuture<?> closeReceived = new CompletableFuture<>();
   116     private final CompletableFuture<?> closeReceived = new CompletableFuture<>();
   106     private final CompletableFuture<?> closeSent = new CompletableFuture<>();
   117     private final CompletableFuture<?> closeSent = new CompletableFuture<>();
   107 
   118 
       
   119     /** Returns the security permission required for the given details. */
       
   120     static URLPermission permissionForServer(URI uri,
       
   121                                              Collection<Pair<String, String>> headers) {
       
   122         StringBuilder sb = new StringBuilder();
       
   123         sb.append(uri.getScheme()).append("://")
       
   124           .append(uri.getAuthority())
       
   125           .append(uri.getPath());
       
   126         String urlstring = sb.toString();
       
   127 
       
   128         String actionstring = headers.stream()
       
   129                 .map(p -> p.first)
       
   130                 .distinct()
       
   131                 .collect(joining(","));
       
   132         if (actionstring != null && !actionstring.equals(""))
       
   133             actionstring = ":" + actionstring;     // Note: no method in the action string
       
   134 
       
   135         return new URLPermission(urlstring, actionstring);
       
   136     }
       
   137 
       
   138     /**
       
   139      * Returns the security permissions required to connect to the proxy, or
       
   140      * null if none is required or applicable.
       
   141      */
       
   142     static URLPermission permissionForProxy(Proxy proxy) {
       
   143         InetSocketAddress proxyAddress = (InetSocketAddress)proxy.address();
       
   144 
       
   145         StringBuilder sb = new StringBuilder();
       
   146         sb.append("socket://")
       
   147           .append(proxyAddress.getHostString()).append(":")
       
   148           .append(proxyAddress.getPort());
       
   149         String urlstring = sb.toString();
       
   150         return new URLPermission(urlstring.toString(), "CONNECT");
       
   151     }
       
   152 
       
   153     /**
       
   154      * Returns the proxy for the given URI when sent through the given client,
       
   155      * or null if none is required or applicable.
       
   156      */
       
   157     static Proxy proxyFor(HttpClient client, URI uri) {
       
   158         Optional<ProxySelector> optional = client.proxy();
       
   159         if (!optional.isPresent())
       
   160             return null;
       
   161 
       
   162         uri = OpeningHandshake.createRequestURI(uri);  // based on the HTTP scheme
       
   163         List<Proxy> pl = optional.get().select(uri);
       
   164         if (pl.size() < 1)
       
   165             return null;
       
   166 
       
   167         Proxy proxy = pl.get(0);
       
   168         if (!proxy.type().equals(Proxy.Type.HTTP))
       
   169             return null;
       
   170 
       
   171         return proxy;
       
   172     }
       
   173 
       
   174     /**
       
   175      * Performs the necessary security permissions checks to connect ( possibly
       
   176      * through a proxy ) to the builders WebSocket URI.
       
   177      *
       
   178      * @throws SecurityException if the security manager denies access
       
   179      */
       
   180     static void checkPermissions(BuilderImpl b, Proxy proxy) {
       
   181         SecurityManager sm = System.getSecurityManager();
       
   182         if (sm != null) {
       
   183             sm.checkPermission(permissionForServer(b.getUri(), b.getHeaders()));
       
   184             if (proxy != null) {
       
   185                 URLPermission perm = permissionForProxy(proxy);
       
   186                 if (perm != null)
       
   187                     sm.checkPermission(perm);
       
   188             }
       
   189         }
       
   190     }
       
   191 
   108     static CompletableFuture<WebSocket> newInstanceAsync(BuilderImpl b) {
   192     static CompletableFuture<WebSocket> newInstanceAsync(BuilderImpl b) {
       
   193         Proxy proxy = proxyFor(b.getClient(), b.getUri());
       
   194         try {
       
   195             checkPermissions(b, proxy);
       
   196         } catch (Throwable throwable) {
       
   197             return failedFuture(throwable);
       
   198         }
       
   199 
   109         Function<Result, WebSocket> newWebSocket = r -> {
   200         Function<Result, WebSocket> newWebSocket = r -> {
   110             WebSocketImpl ws = new WebSocketImpl(b.getUri(),
   201             WebSocketImpl ws = new WebSocketImpl(b.getUri(),
   111                                                  r.subprotocol,
   202                                                  r.subprotocol,
   112                                                  r.channel,
   203                                                  r.channel,
   113                                                  b.getListener());
   204                                                  b.getListener());
   117             ws.signalOpen();
   208             ws.signalOpen();
   118             return ws;
   209             return ws;
   119         };
   210         };
   120         OpeningHandshake h;
   211         OpeningHandshake h;
   121         try {
   212         try {
   122             h = new OpeningHandshake(b);
   213             h = new OpeningHandshake(b, proxy);
   123         } catch (IllegalArgumentException e) {
   214         } catch (IllegalArgumentException e) {
   124             return failedFuture(e);
   215             return failedFuture(e);
   125         }
   216         }
   126         return h.send().thenApply(newWebSocket);
   217         return h.send().thenApply(newWebSocket);
   127     }
   218     }