src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClient.java
branchhttp-client-branch
changeset 56089 42208b2f224e
parent 56088 38fac6d0521d
child 56090 5c7fb702948a
equal deleted inserted replaced
56088:38fac6d0521d 56089:42208b2f224e
     1 /*
       
     2  * Copyright (c) 2015, 2018, 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.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.incubator.http;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.net.Authenticator;
       
    30 import java.net.CookieHandler;
       
    31 import java.net.InetSocketAddress;
       
    32 import java.net.Proxy;
       
    33 import java.net.ProxySelector;
       
    34 import java.util.Optional;
       
    35 import java.util.concurrent.CompletableFuture;
       
    36 import java.util.concurrent.Executor;
       
    37 import java.util.concurrent.Executors;
       
    38 import java.util.concurrent.ThreadFactory;
       
    39 import javax.net.ssl.SSLContext;
       
    40 import javax.net.ssl.SSLParameters;
       
    41 import jdk.incubator.http.HttpResponse.BodyHandler;
       
    42 import jdk.incubator.http.HttpResponse.PushPromiseHandler;
       
    43 import jdk.incubator.http.internal.HttpClientBuilderImpl;
       
    44 
       
    45 /**
       
    46  * An HTTP Client.
       
    47  *
       
    48  * <p> An {@code HttpClient} can be used to send requests and retrieve their
       
    49  * responses. An {@code HttpClient} is created through a {@link
       
    50  * HttpClient#newBuilder() builder}. The builder can be used to configure
       
    51  * per-client state, like: the preferred protocol version ( HTTP/1.1 or HTTP/2 ),
       
    52  * whether to follow redirects, a proxy, an authenticator, etc. Once built, an
       
    53  * {@code HttpClient} is immutable, and can be used to send multiple requests.
       
    54  *
       
    55  * <p> An {@code HttpClient} provides configuration information, and resource
       
    56  * sharing, for all requests send through it.
       
    57  *
       
    58  * <p>For Example:
       
    59  * <pre>{@code    HttpClient client = HttpClient.newBuilder()
       
    60  *        .version(Version.HTTP_2)
       
    61  *        .followRedirects(Redirect.SAME_PROTOCOL)
       
    62  *        .proxy(ProxySelector.of(new InetSocketAddress("proxy.com", 8080)))
       
    63  *        .authenticator(Authenticator.getDefault())
       
    64  *        .build();
       
    65  *
       
    66  *   HttpRequest request = HttpRequest.newBuilder()
       
    67  *        .uri(URI.create("http://foo.com/"))
       
    68  *        .timeout(Duration.ofMinutes(1))
       
    69  *        .header("Content-Type", "application/json")
       
    70  *        .POST(BodyPublisher.fromFile(Paths.get("file.json")))
       
    71  *        .build();
       
    72  *
       
    73  *   client.sendAsync(request, BodyHandler.asString())
       
    74  *        .thenApply(HttpResponse::body)
       
    75  *        .thenAccept(System.out::println)
       
    76  *        .join();  }</pre>
       
    77  *
       
    78  * <p> See {@link HttpRequest} for further examples of usage of this API.
       
    79  *
       
    80  * @since 11
       
    81  */
       
    82 public abstract class HttpClient {
       
    83 
       
    84     /**
       
    85      * Creates an HttpClient.
       
    86      */
       
    87     protected HttpClient() {}
       
    88 
       
    89     /**
       
    90      * Returns a new HttpClient with default settings.
       
    91      *
       
    92      * <p> Equivalent to {@code newBuilder().build()}.
       
    93      *
       
    94      * <p> The default settings include: the "GET" request method, a preference
       
    95      * of {@linkplain HttpClient.Version#HTTP_2 HTTP/2}, a redirection policy of
       
    96      * {@linkplain Redirect#NEVER NEVER}, the {@linkplain
       
    97      * ProxySelector#getDefault() default proxy selector}, and the {@linkplain
       
    98      * SSLContext#getDefault() default SSL context}.
       
    99      *
       
   100      * @implNote The system-wide default values are retrieved at the time the
       
   101      * {@code HttpClient} instance is constructed. Changing the system-wide
       
   102      * values after an {@code HttpClient} instance has been built, for
       
   103      * instance, by calling {@link ProxySelector#setDefault(ProxySelector)}
       
   104      * or {@link SSLContext#setDefault(SSLContext)}, has no effect on already
       
   105      * built instances.
       
   106      *
       
   107      * @return a new HttpClient
       
   108      */
       
   109     public static HttpClient newHttpClient() {
       
   110         return newBuilder().build();
       
   111     }
       
   112 
       
   113     /**
       
   114      * Creates a new {@code HttpClient} builder.
       
   115      *
       
   116      * @return a {@code HttpClient.Builder}
       
   117      */
       
   118     public static Builder newBuilder() {
       
   119         return new HttpClientBuilderImpl();
       
   120     }
       
   121 
       
   122     /**
       
   123      * A builder of immutable {@link HttpClient}s.
       
   124      *
       
   125      * <p> Builders are created by invoking {@linkplain HttpClient#newBuilder()
       
   126      * newBuilder}. Each of the setter methods modifies the state of the builder
       
   127      * and returns the same instance. Builders are not thread-safe and should not be
       
   128      * used concurrently from multiple threads without external synchronization.
       
   129      *
       
   130      * @since 11
       
   131      */
       
   132     public abstract static class Builder {
       
   133 
       
   134         /**
       
   135          * A proxy selector that always return {@link Proxy#NO_PROXY} implying
       
   136          * a direct connection.
       
   137          *
       
   138          * <p> This is a convenience object that can be passed to
       
   139          * {@link #proxy(ProxySelector)} in order to build an instance of
       
   140          * {@link HttpClient} that uses no proxy.
       
   141          */
       
   142         public static final ProxySelector NO_PROXY = ProxySelector.of(null);
       
   143 
       
   144         /**
       
   145          * Creates a Builder.
       
   146          */
       
   147         protected Builder() {}
       
   148 
       
   149         /**
       
   150          * Sets a cookie handler.
       
   151          *
       
   152          * @param cookieHandler the cookie handler
       
   153          * @return this builder
       
   154          */
       
   155         public abstract Builder cookieHandler(CookieHandler cookieHandler);
       
   156 
       
   157         /**
       
   158          * Sets an {@code SSLContext}.
       
   159          *
       
   160          * <p> If this method is not invoked prior to {@linkplain #build()
       
   161          * building}, then newly built clients will use the {@linkplain
       
   162          * SSLContext#getDefault() default context}, which is normally adequate
       
   163          * for client applications that do not need to specify protocols, or
       
   164          * require client authentication.
       
   165          *
       
   166          * @param sslContext the SSLContext
       
   167          * @return this builder
       
   168          */
       
   169         public abstract Builder sslContext(SSLContext sslContext);
       
   170 
       
   171         /**
       
   172          * Sets an {@code SSLParameters}.
       
   173          *
       
   174          * <p> If this method is not invoked prior to {@linkplain #build()
       
   175          * building}, then newly built clients will use a default,
       
   176          * implementation specific, set of parameters.
       
   177          *
       
   178          * <p> Some parameters which are used internally by the HTTP Client
       
   179          * implementation (such as the application protocol list) should not be
       
   180          * set by callers, as they may be ignored. The contents of the given
       
   181          * object are copied.
       
   182          *
       
   183          * @param sslParameters the SSLParameters
       
   184          * @return this builder
       
   185          */
       
   186         public abstract Builder sslParameters(SSLParameters sslParameters);
       
   187 
       
   188         /**
       
   189          * Sets the executor to be used for asynchronous and dependent tasks.
       
   190          *
       
   191          * <p> If this method is not invoked prior to {@linkplain #build()
       
   192          * building}, a default executor is created for each newly built {@code
       
   193          * HttpClient}. The default executor uses a {@linkplain
       
   194          * Executors#newCachedThreadPool(ThreadFactory) cached thread pool},
       
   195          * with a custom thread factory.
       
   196          *
       
   197          * @implNote If a security manager has been installed, the thread
       
   198          * factory creates threads that run with an access control context that
       
   199          * has no permissions.
       
   200          *
       
   201          * @param executor the Executor
       
   202          * @return this builder
       
   203          */
       
   204         public abstract Builder executor(Executor executor);
       
   205 
       
   206         /**
       
   207          * Specifies whether requests will automatically follow redirects issued
       
   208          * by the server.
       
   209          *
       
   210          * <p> If this method is not invoked prior to {@linkplain #build()
       
   211          * building}, then newly built clients will use a default redirection
       
   212          * policy of {@link Redirect#NEVER NEVER}.
       
   213          *
       
   214          * @param policy the redirection policy
       
   215          * @return this builder
       
   216          */
       
   217         public abstract Builder followRedirects(Redirect policy);
       
   218 
       
   219         /**
       
   220          * Requests a specific HTTP protocol version where possible.
       
   221          *
       
   222          * <p> If this method is not invoked prior to {@linkplain #build()
       
   223          * building}, then newly built clients will prefer {@linkplain
       
   224          * Version#HTTP_2 HTTP/2}.
       
   225          *
       
   226          * <p> If set to {@linkplain Version#HTTP_2 HTTP/2}, then each request
       
   227          * will attempt to upgrade to HTTP/2. If the upgrade succeeds, then the
       
   228          * response to this request will use HTTP/2 and all subsequent requests
       
   229          * and responses to the same
       
   230          * <a href="https://tools.ietf.org/html/rfc6454#section-4">origin server</a>
       
   231          * will use HTTP/2. If the upgrade fails, then the response will be
       
   232          * handled using HTTP/1.1
       
   233          *
       
   234          * @implNote Constraints may also affect the selection of protocol version.
       
   235          * For example, if HTTP/2 is requested through a proxy, and if the implementation
       
   236          * does not support this mode, then HTTP/1.1 may be used
       
   237          *
       
   238          * @param version the requested HTTP protocol version
       
   239          * @return this builder
       
   240          */
       
   241         public abstract Builder version(HttpClient.Version version);
       
   242 
       
   243         /**
       
   244          * Sets the default priority for any HTTP/2 requests sent from this
       
   245          * client. The value provided must be between {@code 1} and {@code 256}
       
   246          * (inclusive).
       
   247          *
       
   248          * @param priority the priority weighting
       
   249          * @return this builder
       
   250          * @throws IllegalArgumentException if the given priority is out of range
       
   251          */
       
   252         public abstract Builder priority(int priority);
       
   253 
       
   254         /**
       
   255          * Sets a {@link java.net.ProxySelector}.
       
   256          *
       
   257          * @apiNote {@link ProxySelector#of(InetSocketAddress)}
       
   258          * provides a {@code ProxySelector} which uses a single proxy for all
       
   259          * requests. The system-wide proxy selector can be retrieved by
       
   260          * {@link ProxySelector#getDefault()}.
       
   261          *
       
   262          * @implNote
       
   263          * If this method is not invoked prior to {@linkplain #build()
       
   264          * building}, then newly built clients will use the {@linkplain
       
   265          * ProxySelector#getDefault() default proxy selector}, which
       
   266          * is normally adequate for client applications. This default
       
   267          * behavior can be turned off by supplying an explicit proxy
       
   268          * selector to this method, such as {@link #NO_PROXY} or one
       
   269          * returned by {@link ProxySelector#of(InetSocketAddress)},
       
   270          * before calling {@link #build()}.
       
   271          *
       
   272          * @param selector the ProxySelector
       
   273          * @return this builder
       
   274          */
       
   275         public abstract Builder proxy(ProxySelector selector);
       
   276 
       
   277         /**
       
   278          * Sets an authenticator to use for HTTP authentication.
       
   279          *
       
   280          * @param a the Authenticator
       
   281          * @return this builder
       
   282          */
       
   283         public abstract Builder authenticator(Authenticator a);
       
   284 
       
   285         /**
       
   286          * Returns a new {@link HttpClient} built from the current state of this
       
   287          * builder.
       
   288          *
       
   289          * @return this builder
       
   290          */
       
   291         public abstract HttpClient build();
       
   292     }
       
   293 
       
   294 
       
   295     /**
       
   296      * Returns an {@code Optional} containing this client's {@linkplain
       
   297      * CookieHandler}. If no {@code CookieHandler} was set in this client's
       
   298      * builder, then the {@code Optional} is empty.
       
   299      *
       
   300      * @return an {@code Optional} containing this client's {@code CookieHandler}
       
   301      */
       
   302     public abstract Optional<CookieHandler> cookieHandler();
       
   303 
       
   304     /**
       
   305      * Returns the follow redirects policy for this client. The default value
       
   306      * for client's built by builders that do not specify a redirect policy is
       
   307      * {@link HttpClient.Redirect#NEVER NEVER}.
       
   308      *
       
   309      * @return this client's follow redirects setting
       
   310      */
       
   311     public abstract Redirect followRedirects();
       
   312 
       
   313     /**
       
   314      * Returns an {@code Optional} containing the {@code ProxySelector}
       
   315      * supplied to this client. If no proxy selector was set in this client's
       
   316      * builder, then the {@code Optional} is empty.
       
   317      *
       
   318      * <p> Even though this method may return an empty optional, the {@code
       
   319      * HttpClient} may still have an non-exposed {@linkplain
       
   320      * Builder#proxy(ProxySelector) default proxy selector} that is
       
   321      * used for sending HTTP requests.
       
   322      *
       
   323      * @return an {@code Optional} containing the proxy selector supplied
       
   324      *        to this client.
       
   325      */
       
   326     public abstract Optional<ProxySelector> proxy();
       
   327 
       
   328     /**
       
   329      * Returns this client's {@code SSLContext}.
       
   330      *
       
   331      * <p> If no {@code SSLContext} was set in this client's builder, then the
       
   332      * {@linkplain SSLContext#getDefault() default context} is returned.
       
   333      *
       
   334      * @return this client's SSLContext
       
   335      */
       
   336     public abstract SSLContext sslContext();
       
   337 
       
   338     /**
       
   339      * Returns a copy of this client's {@link SSLParameters}.
       
   340      *
       
   341      * <p> If no {@code SSLParameters} were set in the client's builder, then an
       
   342      * implementation specific default set of parameters, that the client will
       
   343      * use, is returned.
       
   344      *
       
   345      * @return this client's {@code SSLParameters}
       
   346      */
       
   347     public abstract SSLParameters sslParameters();
       
   348 
       
   349     /**
       
   350      * Returns an {@code Optional} containing the {@link Authenticator} set on
       
   351      * this client. If no {@code Authenticator} was set in the client's builder,
       
   352      * then the {@code Optional} is empty.
       
   353      *
       
   354      * @return an {@code Optional} containing this client's {@code Authenticator}
       
   355      */
       
   356     public abstract Optional<Authenticator> authenticator();
       
   357 
       
   358     /**
       
   359      * Returns the preferred HTTP protocol version for this client. The default
       
   360      * value is {@link HttpClient.Version#HTTP_2}
       
   361      *
       
   362      * @implNote Constraints may also affect the selection of protocol version.
       
   363      * For example, if HTTP/2 is requested through a proxy, and if the
       
   364      * implementation does not support this mode, then HTTP/1.1 may be used
       
   365      *
       
   366      * @return the HTTP protocol version requested
       
   367      */
       
   368     public abstract HttpClient.Version version();
       
   369 
       
   370     /**
       
   371      * Returns an {@code Optional} containing this client's {@linkplain
       
   372      * Executor}. If no {@code Executor} was set in the client's builder,
       
   373      * then the {@code Optional} is empty.
       
   374      *
       
   375      * <p> Even though this method may return an empty optional, the {@code
       
   376      * HttpClient} may still have an non-exposed {@linkplain
       
   377      * HttpClient.Builder#executor(Executor) default executor} that is used for
       
   378      * executing asynchronous and dependent tasks.
       
   379      *
       
   380      * @return an {@code Optional} containing this client's {@code Executor}
       
   381      */
       
   382     public abstract Optional<Executor> executor();
       
   383 
       
   384     /**
       
   385      * The HTTP protocol version.
       
   386      *
       
   387      * @since 11
       
   388      */
       
   389     public enum Version {
       
   390 
       
   391         /**
       
   392          * HTTP version 1.1
       
   393          */
       
   394         HTTP_1_1,
       
   395 
       
   396         /**
       
   397          * HTTP version 2
       
   398          */
       
   399         HTTP_2
       
   400     }
       
   401 
       
   402     /**
       
   403      * Defines automatic redirection policy.
       
   404      *
       
   405      * <p> This is checked whenever a {@code 3XX} response code is received. If
       
   406      * redirection does not happen automatically then the response is returned
       
   407      * to the user, where it can be handled manually.
       
   408      *
       
   409      * <p> {@code Redirect} policy is set via the {@link
       
   410      * HttpClient.Builder#followRedirects(HttpClient.Redirect)} method.
       
   411      *
       
   412      * @since 11
       
   413      */
       
   414     public enum Redirect {
       
   415 
       
   416         /**
       
   417          * Never redirect.
       
   418          */
       
   419         NEVER,
       
   420 
       
   421         /**
       
   422          * Always redirect.
       
   423          */
       
   424         ALWAYS,
       
   425 
       
   426         /**
       
   427          * Redirect to same protocol only. Redirection may occur from HTTP URLs
       
   428          * to other HTTP URLs, and from HTTPS URLs to other HTTPS URLs.
       
   429          */
       
   430         SAME_PROTOCOL,
       
   431 
       
   432         /**
       
   433          * Redirect always except from HTTPS URLs to HTTP URLs.
       
   434          */
       
   435         SECURE
       
   436     }
       
   437 
       
   438     /**
       
   439      * Sends the given request using this client, blocking if necessary to get
       
   440      * the response. The returned {@link HttpResponse}{@code <T>} contains the
       
   441      * response status, headers, and body ( as handled by given response body
       
   442      * handler ).
       
   443      *
       
   444      * @param <T> the response body type
       
   445      * @param req the request
       
   446      * @param responseBodyHandler the response body handler
       
   447      * @return the response body
       
   448      * @throws IOException if an I/O error occurs when sending or receiving
       
   449      * @throws InterruptedException if the operation is interrupted
       
   450      * @throws IllegalArgumentException if the request method is not supported
       
   451      * @throws SecurityException If a security manager has been installed
       
   452      *          and it denies {@link java.net.URLPermission access} to the
       
   453      *          URL in the given request, or proxy if one is configured.
       
   454      *          See HttpRequest for further information about
       
   455      *          <a href="HttpRequest.html#securitychecks">security checks</a>.
       
   456      */
       
   457     public abstract <T> HttpResponse<T>
       
   458     send(HttpRequest req, HttpResponse.BodyHandler<T> responseBodyHandler)
       
   459         throws IOException, InterruptedException;
       
   460 
       
   461     /**
       
   462      * Sends the given request asynchronously using this client and the given
       
   463      * response handler.
       
   464      *
       
   465      * <p> Equivalent to {@code sendAsync(request, responseBodyHandler, null)}.
       
   466      *
       
   467      * @param <T> the response body type
       
   468      * @param request the request
       
   469      * @param responseBodyHandler the response body handler
       
   470      * @return a {@code CompletableFuture<HttpResponse<T>>}
       
   471      */
       
   472     public abstract <T> CompletableFuture<HttpResponse<T>>
       
   473     sendAsync(HttpRequest request,
       
   474               BodyHandler<T> responseBodyHandler);
       
   475 
       
   476     /**
       
   477      * Sends the given request asynchronously using this client with the given
       
   478      * response body handler and push promise handler.
       
   479      *
       
   480      * <p> The returned completable future, if completed successfully, completes
       
   481      * with an {@link HttpResponse}{@code <T>} that contains the response status,
       
   482      * headers, and body ( as handled by given response body handler ).
       
   483      *
       
   484      * <p> {@linkplain PushPromiseHandler Push promises} received, if any, are
       
   485      * handled by the given {@code pushPromiseHandler}. A {@code null} valued
       
   486      * {@code pushPromiseHandler} rejects any push promises.
       
   487      *
       
   488      * <p> The returned completable future completes exceptionally with:
       
   489      * <ul>
       
   490      * <li>{@link IOException} - if an I/O error occurs when sending or receiving</li>
       
   491      * <li>{@link IllegalArgumentException} - if the request method is not supported</li>
       
   492      * <li>{@link SecurityException} - If a security manager has been installed
       
   493      *          and it denies {@link java.net.URLPermission access} to the
       
   494      *          URL in the given request, or proxy if one is configured.
       
   495      *          See HttpRequest for further information about
       
   496      *          <a href="HttpRequest.html#securitychecks">security checks</a>.</li>
       
   497      * </ul>
       
   498      *
       
   499      * @param <T> the response body type
       
   500      * @param request the request
       
   501      * @param responseBodyHandler the response body handler
       
   502      * @param pushPromiseHandler push promise handler, may be null
       
   503      * @return a {@code CompletableFuture<HttpResponse<T>>}
       
   504      */
       
   505     public abstract <T> CompletableFuture<HttpResponse<T>>
       
   506     sendAsync(HttpRequest request,
       
   507               BodyHandler<T> responseBodyHandler,
       
   508               PushPromiseHandler<T> pushPromiseHandler);
       
   509 
       
   510     /**
       
   511      * Creates a new {@code WebSocket} builder (optional operation).
       
   512      *
       
   513      * <p> <b>Example</b>
       
   514      * <pre>{@code
       
   515      *     HttpClient client = HttpClient.newHttpClient();
       
   516      *     CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
       
   517      *             .buildAsync(URI.create("ws://websocket.example.com"), listener);
       
   518      * }</pre>
       
   519      *
       
   520      * <p> Finer control over the WebSocket Opening Handshake can be achieved
       
   521      * by using a custom {@code HttpClient}.
       
   522      *
       
   523      * <p> <b>Example</b>
       
   524      * <pre>{@code
       
   525      *     InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
       
   526      *     HttpClient client = HttpClient.newBuilder()
       
   527      *             .proxy(ProxySelector.of(addr))
       
   528      *             .build();
       
   529      *     CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
       
   530      *             .buildAsync(URI.create("ws://websocket.example.com"), listener);
       
   531      * }</pre>
       
   532      *
       
   533      * <p> A {@code WebSocket.Builder} returned from this method is not safe for
       
   534      * use by multiple threads without external synchronization.
       
   535      *
       
   536      * @implSpec The default implementation of this method throws
       
   537      * {@code UnsupportedOperationException}. Clients obtained through
       
   538      * {@link HttpClient#newHttpClient()} or {@link HttpClient#newBuilder()}
       
   539      * return a {@code WebSocket} builder.
       
   540      *
       
   541      * @implNote Both builder and {@code WebSocket}s created with it operate in
       
   542      * a non-blocking fashion. That is, their methods do not block before
       
   543      * returning a {@code CompletableFuture}. Asynchronous tasks are executed in
       
   544      * this {@code HttpClient}'s executor.
       
   545      *
       
   546      * <p> When a {@code CompletionStage} returned from
       
   547      * {@link WebSocket.Listener#onClose Listener.onClose} completes,
       
   548      * the {@code WebSocket} will send a Close message that has the same code
       
   549      * the received message has and an empty reason.
       
   550      *
       
   551      * @return a {@code WebSocket.Builder}
       
   552      * @throws UnsupportedOperationException
       
   553      *         if this {@code HttpClient} does not provide WebSocket support
       
   554      */
       
   555     public WebSocket.Builder newWebSocketBuilder() {
       
   556         throw new UnsupportedOperationException();
       
   557     }
       
   558 }