mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-22 20:14:43 +02:00
8197564: HTTP Client implementation
Co-authored-by: Daniel Fuchs <daniel.fuchs@oracle.com> Co-authored-by: Michael McMahon <michael.x.mcmahon@oracle.com> Co-authored-by: Pavel Rappo <pavel.rappo@oracle.com> Reviewed-by: chegar, dfuchs, michaelm, prappo
This commit is contained in:
parent
a9234c0ab6
commit
a3b61fd4c7
398 changed files with 37643 additions and 10897 deletions
605
src/java.net.http/share/classes/java/net/http/HttpClient.java
Normal file
605
src/java.net.http/share/classes/java/net/http/HttpClient.java
Normal file
|
@ -0,0 +1,605 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Authenticator;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URLPermission;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import java.net.http.HttpResponse.BodyHandler;
|
||||
import java.net.http.HttpResponse.PushPromiseHandler;
|
||||
import jdk.internal.net.http.HttpClientBuilderImpl;
|
||||
|
||||
/**
|
||||
* An HTTP Client.
|
||||
*
|
||||
* <p> An {@code HttpClient} can be used to send {@linkplain HttpRequest
|
||||
* requests} and retrieve their {@linkplain HttpResponse responses}. An {@code
|
||||
* HttpClient} is created through a {@link HttpClient#newBuilder() builder}. The
|
||||
* builder can be used to configure per-client state, like: the preferred
|
||||
* protocol version ( HTTP/1.1 or HTTP/2 ), whether to follow redirects, a
|
||||
* proxy, an authenticator, etc. Once built, an {@code HttpClient} is immutable,
|
||||
* and can be used to send multiple requests.
|
||||
*
|
||||
* <p> An {@code HttpClient} provides configuration information, and resource
|
||||
* sharing, for all requests send through it.
|
||||
*
|
||||
* <p> A {@link BodyHandler BodyHandler} must be supplied for each {@link
|
||||
* HttpRequest} sent. The {@code BodyHandler} determines how to handle the
|
||||
* response body, if any. Once an {@link HttpResponse} is received, the
|
||||
* headers, response code, and body (typically) are available. Whether the
|
||||
* response body bytes have been read or not depends on the type, {@code T}, of
|
||||
* the response body.
|
||||
*
|
||||
* <p> Requests can be sent either synchronously or asynchronously:
|
||||
* <ul>
|
||||
* <li>{@link HttpClient#send(HttpRequest, BodyHandler)} blocks
|
||||
* until the request has been sent and the response has been received.</li>
|
||||
*
|
||||
* <li>{@link HttpClient#sendAsync(HttpRequest, BodyHandler)} sends the
|
||||
* request and receives the response asynchronously. The {@code sendAsync}
|
||||
* method returns immediately with a {@link CompletableFuture
|
||||
* CompletableFuture}<{@link HttpResponse}>. The {@code
|
||||
* CompletableFuture} completes when the response becomes available. The
|
||||
* returned {@code CompletableFuture} can be combined in different ways to
|
||||
* declare dependencies among several asynchronous tasks.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>Synchronous Example</b>
|
||||
* <pre>{@code HttpClient client = HttpClient.newBuilder()
|
||||
* .version(Version.HTTP_1_1)
|
||||
* .followRedirects(Redirect.NORMAL)
|
||||
* .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
|
||||
* .authenticator(Authenticator.getDefault())
|
||||
* .build();
|
||||
* HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
|
||||
* System.out.println(response.statusCode());
|
||||
* System.out.println(response.body()); }</pre>
|
||||
*
|
||||
* <p><b>Asynchronous Example</b>
|
||||
* <pre>{@code HttpRequest request = HttpRequest.newBuilder()
|
||||
* .uri(URI.create("https://foo.com/"))
|
||||
* .timeout(Duration.ofMinutes(1))
|
||||
* .header("Content-Type", "application/json")
|
||||
* .POST(BodyPublishers.ofFile(Paths.get("file.json")))
|
||||
* .build();
|
||||
* client.sendAsync(request, BodyHandlers.ofString())
|
||||
* .thenApply(HttpResponse::body)
|
||||
* .thenAccept(System.out::println); }</pre>
|
||||
*
|
||||
* <p> <a id="securitychecks"></a><b>Security checks</b></a>
|
||||
*
|
||||
* <p> If a security manager is present then security checks are performed by
|
||||
* the HTTP Client's sending methods. An appropriate {@link URLPermission} is
|
||||
* required to access the destination server, and proxy server if one has
|
||||
* been configured. The form of the {@code URLPermission} required to access a
|
||||
* proxy has a {@code method} parameter of {@code "CONNECT"} (for all kinds of
|
||||
* proxying) and a {@code URL} string of the form {@code "socket://host:port"}
|
||||
* where host and port specify the proxy's address.
|
||||
*
|
||||
* @implNote If an explicit {@linkplain HttpClient.Builder#executor(Executor)
|
||||
* executor} has not been set for an {@code HttpClient}, and a security manager
|
||||
* has been installed, then the default executor will execute asynchronous and
|
||||
* dependent tasks in a context that is granted no permissions. Custom
|
||||
* {@linkplain HttpRequest.BodyPublisher request body publishers}, {@linkplain
|
||||
* HttpResponse.BodyHandler response body handlers}, {@linkplain
|
||||
* HttpResponse.BodySubscriber response body subscribers}, and {@linkplain
|
||||
* WebSocket.Listener WebSocket Listeners}, if executing operations that require
|
||||
* privileges, should do so within an appropriate {@linkplain
|
||||
* AccessController#doPrivileged(PrivilegedAction) privileged context}.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public abstract class HttpClient {
|
||||
|
||||
/**
|
||||
* Creates an HttpClient.
|
||||
*/
|
||||
protected HttpClient() {}
|
||||
|
||||
/**
|
||||
* Returns a new {@code HttpClient} with default settings.
|
||||
*
|
||||
* <p> Equivalent to {@code newBuilder().build()}.
|
||||
*
|
||||
* <p> The default settings include: the "GET" request method, a preference
|
||||
* of {@linkplain HttpClient.Version#HTTP_2 HTTP/2}, a redirection policy of
|
||||
* {@linkplain Redirect#NEVER NEVER}, the {@linkplain
|
||||
* ProxySelector#getDefault() default proxy selector}, and the {@linkplain
|
||||
* SSLContext#getDefault() default SSL context}.
|
||||
*
|
||||
* @implNote The system-wide default values are retrieved at the time the
|
||||
* {@code HttpClient} instance is constructed. Changing the system-wide
|
||||
* values after an {@code HttpClient} instance has been built, for
|
||||
* instance, by calling {@link ProxySelector#setDefault(ProxySelector)}
|
||||
* or {@link SSLContext#setDefault(SSLContext)}, has no effect on already
|
||||
* built instances.
|
||||
*
|
||||
* @return a new HttpClient
|
||||
*/
|
||||
public static HttpClient newHttpClient() {
|
||||
return newBuilder().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code HttpClient} builder.
|
||||
*
|
||||
* @return an {@code HttpClient.Builder}
|
||||
*/
|
||||
public static Builder newBuilder() {
|
||||
return new HttpClientBuilderImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder of {@linkplain HttpClient HTTP Clients}.
|
||||
*
|
||||
* <p> Builders are created by invoking {@link HttpClient#newBuilder()
|
||||
* newBuilder}. Each of the setter methods modifies the state of the builder
|
||||
* and returns the same instance. Builders are not thread-safe and should not be
|
||||
* used concurrently from multiple threads without external synchronization.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public interface Builder {
|
||||
|
||||
/**
|
||||
* A proxy selector that always return {@link Proxy#NO_PROXY} implying
|
||||
* a direct connection.
|
||||
*
|
||||
* <p> This is a convenience object that can be passed to
|
||||
* {@link #proxy(ProxySelector)} in order to build an instance of
|
||||
* {@link HttpClient} that uses no proxy.
|
||||
*/
|
||||
public static final ProxySelector NO_PROXY = ProxySelector.of(null);
|
||||
|
||||
|
||||
/**
|
||||
* Sets a cookie handler.
|
||||
*
|
||||
* @param cookieHandler the cookie handler
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder cookieHandler(CookieHandler cookieHandler);
|
||||
|
||||
/**
|
||||
* Sets an {@code SSLContext}.
|
||||
*
|
||||
* <p> If this method is not invoked prior to {@linkplain #build()
|
||||
* building}, then newly built clients will use the {@linkplain
|
||||
* SSLContext#getDefault() default context}, which is normally adequate
|
||||
* for client applications that do not need to specify protocols, or
|
||||
* require client authentication.
|
||||
*
|
||||
* @param sslContext the SSLContext
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder sslContext(SSLContext sslContext);
|
||||
|
||||
/**
|
||||
* Sets an {@code SSLParameters}.
|
||||
*
|
||||
* <p> If this method is not invoked prior to {@linkplain #build()
|
||||
* building}, then newly built clients will use a default,
|
||||
* implementation specific, set of parameters.
|
||||
*
|
||||
* <p> Some parameters which are used internally by the HTTP Client
|
||||
* implementation (such as the application protocol list) should not be
|
||||
* set by callers, as they may be ignored. The contents of the given
|
||||
* object are copied.
|
||||
*
|
||||
* @param sslParameters the SSLParameters
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder sslParameters(SSLParameters sslParameters);
|
||||
|
||||
/**
|
||||
* Sets the executor to be used for asynchronous and dependent tasks.
|
||||
*
|
||||
* <p> If this method is not invoked prior to {@linkplain #build()
|
||||
* building}, a default executor is created for each newly built {@code
|
||||
* HttpClient}. The default executor uses a {@linkplain
|
||||
* Executors#newCachedThreadPool(ThreadFactory) cached thread pool},
|
||||
* with a custom thread factory.
|
||||
*
|
||||
* @implNote If a security manager has been installed, the thread
|
||||
* factory creates threads that run with an access control context that
|
||||
* has no permissions.
|
||||
*
|
||||
* @param executor the Executor
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder executor(Executor executor);
|
||||
|
||||
/**
|
||||
* Specifies whether requests will automatically follow redirects issued
|
||||
* by the server.
|
||||
*
|
||||
* <p> If this method is not invoked prior to {@linkplain #build()
|
||||
* building}, then newly built clients will use a default redirection
|
||||
* policy of {@link Redirect#NEVER NEVER}.
|
||||
*
|
||||
* @param policy the redirection policy
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder followRedirects(Redirect policy);
|
||||
|
||||
/**
|
||||
* Requests a specific HTTP protocol version where possible.
|
||||
*
|
||||
* <p> If this method is not invoked prior to {@linkplain #build()
|
||||
* building}, then newly built clients will prefer {@linkplain
|
||||
* Version#HTTP_2 HTTP/2}.
|
||||
*
|
||||
* <p> If set to {@linkplain Version#HTTP_2 HTTP/2}, then each request
|
||||
* will attempt to upgrade to HTTP/2. If the upgrade succeeds, then the
|
||||
* response to this request will use HTTP/2 and all subsequent requests
|
||||
* and responses to the same
|
||||
* <a href="https://tools.ietf.org/html/rfc6454#section-4">origin server</a>
|
||||
* will use HTTP/2. If the upgrade fails, then the response will be
|
||||
* handled using HTTP/1.1
|
||||
*
|
||||
* @implNote Constraints may also affect the selection of protocol version.
|
||||
* For example, if HTTP/2 is requested through a proxy, and if the implementation
|
||||
* does not support this mode, then HTTP/1.1 may be used
|
||||
*
|
||||
* @param version the requested HTTP protocol version
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder version(HttpClient.Version version);
|
||||
|
||||
/**
|
||||
* Sets the default priority for any HTTP/2 requests sent from this
|
||||
* client. The value provided must be between {@code 1} and {@code 256}
|
||||
* (inclusive).
|
||||
*
|
||||
* @param priority the priority weighting
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if the given priority is out of range
|
||||
*/
|
||||
public Builder priority(int priority);
|
||||
|
||||
/**
|
||||
* Sets a {@link java.net.ProxySelector}.
|
||||
*
|
||||
* @apiNote {@link ProxySelector#of(InetSocketAddress) ProxySelector::of}
|
||||
* provides a {@code ProxySelector} which uses a single proxy for all
|
||||
* requests. The system-wide proxy selector can be retrieved by
|
||||
* {@link ProxySelector#getDefault()}.
|
||||
*
|
||||
* @implNote
|
||||
* If this method is not invoked prior to {@linkplain #build() building},
|
||||
* then newly built clients will use the {@linkplain
|
||||
* ProxySelector#getDefault() default proxy selector}, which is usually
|
||||
* adequate for client applications. The default proxy selector supports
|
||||
* a set of system properties</a> related to
|
||||
* <a href="{@docRoot}/java.base/java/net/doc-files/net-properties.html#Proxies">
|
||||
* proxy settings</a>. This default behavior can be disabled by
|
||||
* supplying an explicit proxy selector, such as {@link #NO_PROXY} or
|
||||
* one returned by {@link ProxySelector#of(InetSocketAddress)
|
||||
* ProxySelector::of}, before {@linkplain #build() building}.
|
||||
*
|
||||
* @param proxySelector the ProxySelector
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder proxy(ProxySelector proxySelector);
|
||||
|
||||
/**
|
||||
* Sets an authenticator to use for HTTP authentication.
|
||||
*
|
||||
* @param authenticator the Authenticator
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder authenticator(Authenticator authenticator);
|
||||
|
||||
/**
|
||||
* Returns a new {@link HttpClient} built from the current state of this
|
||||
* builder.
|
||||
*
|
||||
* @return a new {@code HttpClient}
|
||||
*/
|
||||
public HttpClient build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing this client's {@link
|
||||
* CookieHandler}. If no {@code CookieHandler} was set in this client's
|
||||
* builder, then the {@code Optional} is empty.
|
||||
*
|
||||
* @return an {@code Optional} containing this client's {@code CookieHandler}
|
||||
*/
|
||||
public abstract Optional<CookieHandler> cookieHandler();
|
||||
|
||||
/**
|
||||
* Returns the follow redirects policy for this client. The default value
|
||||
* for client's built by builders that do not specify a redirect policy is
|
||||
* {@link HttpClient.Redirect#NEVER NEVER}.
|
||||
*
|
||||
* @return this client's follow redirects setting
|
||||
*/
|
||||
public abstract Redirect followRedirects();
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing the {@code ProxySelector}
|
||||
* supplied to this client. If no proxy selector was set in this client's
|
||||
* builder, then the {@code Optional} is empty.
|
||||
*
|
||||
* <p> Even though this method may return an empty optional, the {@code
|
||||
* HttpClient} may still have a non-exposed {@linkplain
|
||||
* Builder#proxy(ProxySelector) default proxy selector} that is
|
||||
* used for sending HTTP requests.
|
||||
*
|
||||
* @return an {@code Optional} containing the proxy selector supplied
|
||||
* to this client.
|
||||
*/
|
||||
public abstract Optional<ProxySelector> proxy();
|
||||
|
||||
/**
|
||||
* Returns this client's {@code SSLContext}.
|
||||
*
|
||||
* <p> If no {@code SSLContext} was set in this client's builder, then the
|
||||
* {@linkplain SSLContext#getDefault() default context} is returned.
|
||||
*
|
||||
* @return this client's SSLContext
|
||||
*/
|
||||
public abstract SSLContext sslContext();
|
||||
|
||||
/**
|
||||
* Returns a copy of this client's {@link SSLParameters}.
|
||||
*
|
||||
* <p> If no {@code SSLParameters} were set in the client's builder, then an
|
||||
* implementation specific default set of parameters, that the client will
|
||||
* use, is returned.
|
||||
*
|
||||
* @return this client's {@code SSLParameters}
|
||||
*/
|
||||
public abstract SSLParameters sslParameters();
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing the {@link Authenticator} set on
|
||||
* this client. If no {@code Authenticator} was set in the client's builder,
|
||||
* then the {@code Optional} is empty.
|
||||
*
|
||||
* @return an {@code Optional} containing this client's {@code Authenticator}
|
||||
*/
|
||||
public abstract Optional<Authenticator> authenticator();
|
||||
|
||||
/**
|
||||
* Returns the preferred HTTP protocol version for this client. The default
|
||||
* value is {@link HttpClient.Version#HTTP_2}
|
||||
*
|
||||
* @implNote Constraints may also affect the selection of protocol version.
|
||||
* For example, if HTTP/2 is requested through a proxy, and if the
|
||||
* implementation does not support this mode, then HTTP/1.1 may be used
|
||||
*
|
||||
* @return the HTTP protocol version requested
|
||||
*/
|
||||
public abstract HttpClient.Version version();
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing this client's {@link
|
||||
* Executor}. If no {@code Executor} was set in the client's builder,
|
||||
* then the {@code Optional} is empty.
|
||||
*
|
||||
* <p> Even though this method may return an empty optional, the {@code
|
||||
* HttpClient} may still have an non-exposed {@linkplain
|
||||
* HttpClient.Builder#executor(Executor) default executor} that is used for
|
||||
* executing asynchronous and dependent tasks.
|
||||
*
|
||||
* @return an {@code Optional} containing this client's {@code Executor}
|
||||
*/
|
||||
public abstract Optional<Executor> executor();
|
||||
|
||||
/**
|
||||
* The HTTP protocol version.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public enum Version {
|
||||
|
||||
/**
|
||||
* HTTP version 1.1
|
||||
*/
|
||||
HTTP_1_1,
|
||||
|
||||
/**
|
||||
* HTTP version 2
|
||||
*/
|
||||
HTTP_2
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the automatic redirection policy.
|
||||
*
|
||||
* <p> The automatic redirection policy is checked whenever a {@code 3XX}
|
||||
* response code is received. If redirection does not happen automatically,
|
||||
* then the response, containing the {@code 3XX} response code, is returned,
|
||||
* where it can be handled manually.
|
||||
*
|
||||
* <p> {@code Redirect} policy is set via the {@linkplain
|
||||
* HttpClient.Builder#followRedirects(Redirect) Builder.followRedirects}
|
||||
* method.
|
||||
*
|
||||
* @implNote When automatic redirection occurs, the request method of the
|
||||
* redirected request may be modified depending on the specific {@code 30X}
|
||||
* status code, as specified in <a href="https://tools.ietf.org/html/rfc7231">
|
||||
* RFC 7231</a>. In addition, the {@code 301} and {@code 302} status codes
|
||||
* cause a {@code POST} request to be converted to a {@code GET} in the
|
||||
* redirected request.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public enum Redirect {
|
||||
|
||||
/**
|
||||
* Never redirect.
|
||||
*/
|
||||
NEVER,
|
||||
|
||||
/**
|
||||
* Always redirect.
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Always redirect, except from HTTPS URLs to HTTP URLs.
|
||||
*/
|
||||
NORMAL
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the given request using this client, blocking if necessary to get
|
||||
* the response. The returned {@link HttpResponse}{@code <T>} contains the
|
||||
* response status, headers, and body ( as handled by given response body
|
||||
* handler ).
|
||||
*
|
||||
* @param <T> the response body type
|
||||
* @param request the request
|
||||
* @param responseBodyHandler the response body handler
|
||||
* @return the response
|
||||
* @throws IOException if an I/O error occurs when sending or receiving
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
* @throws IllegalArgumentException if the {@code request} argument is not
|
||||
* a request that could have been validly built as specified by {@link
|
||||
* HttpRequest.Builder HttpRequest.Builder}.
|
||||
* @throws SecurityException If a security manager has been installed
|
||||
* and it denies {@link java.net.URLPermission access} to the
|
||||
* URL in the given request, or proxy if one is configured.
|
||||
* See <a href="#securitychecks">security checks</a> for further
|
||||
* information.
|
||||
*/
|
||||
public abstract <T> HttpResponse<T>
|
||||
send(HttpRequest request, HttpResponse.BodyHandler<T> responseBodyHandler)
|
||||
throws IOException, InterruptedException;
|
||||
|
||||
/**
|
||||
* Sends the given request asynchronously using this client with the given
|
||||
* response body handler.
|
||||
*
|
||||
* <p> Equivalent to: {@code sendAsync(request, responseBodyHandler, null)}.
|
||||
*
|
||||
* @param <T> the response body type
|
||||
* @param request the request
|
||||
* @param responseBodyHandler the response body handler
|
||||
* @return a {@code CompletableFuture<HttpResponse<T>>}
|
||||
* @throws IllegalArgumentException if the {@code request} argument is not
|
||||
* a request that could have been validly built as specified by {@link
|
||||
* HttpRequest.Builder HttpRequest.Builder}.
|
||||
*/
|
||||
public abstract <T> CompletableFuture<HttpResponse<T>>
|
||||
sendAsync(HttpRequest request,
|
||||
BodyHandler<T> responseBodyHandler);
|
||||
|
||||
/**
|
||||
* Sends the given request asynchronously using this client with the given
|
||||
* response body handler and push promise handler.
|
||||
*
|
||||
* <p> The returned completable future, if completed successfully, completes
|
||||
* with an {@link HttpResponse}{@code <T>} that contains the response status,
|
||||
* headers, and body ( as handled by given response body handler ).
|
||||
*
|
||||
* <p> {@linkplain PushPromiseHandler Push promises} received, if any, are
|
||||
* handled by the given {@code pushPromiseHandler}. A {@code null} valued
|
||||
* {@code pushPromiseHandler} rejects any push promises.
|
||||
*
|
||||
* <p> The returned completable future completes exceptionally with:
|
||||
* <ul>
|
||||
* <li>{@link IOException} - if an I/O error occurs when sending or receiving</li>
|
||||
* <li>{@link SecurityException} - If a security manager has been installed
|
||||
* and it denies {@link java.net.URLPermission access} to the
|
||||
* URL in the given request, or proxy if one is configured.
|
||||
* See <a href="#securitychecks">security checks</a> for further
|
||||
* information.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> the response body type
|
||||
* @param request the request
|
||||
* @param responseBodyHandler the response body handler
|
||||
* @param pushPromiseHandler push promise handler, may be null
|
||||
* @return a {@code CompletableFuture<HttpResponse<T>>}
|
||||
* @throws IllegalArgumentException if the {@code request} argument is not
|
||||
* a request that could have been validly built as specified by {@link
|
||||
* HttpRequest.Builder HttpRequest.Builder}.
|
||||
*/
|
||||
public abstract <T> CompletableFuture<HttpResponse<T>>
|
||||
sendAsync(HttpRequest request,
|
||||
BodyHandler<T> responseBodyHandler,
|
||||
PushPromiseHandler<T> pushPromiseHandler);
|
||||
|
||||
/**
|
||||
* Creates a new {@code WebSocket} builder (optional operation).
|
||||
*
|
||||
* <p> <b>Example</b>
|
||||
* <pre>{@code HttpClient client = HttpClient.newHttpClient();
|
||||
* CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
|
||||
* .buildAsync(URI.create("ws://websocket.example.com"), listener); }</pre>
|
||||
*
|
||||
* <p> Finer control over the WebSocket Opening Handshake can be achieved
|
||||
* by using a custom {@code HttpClient}.
|
||||
*
|
||||
* <p> <b>Example</b>
|
||||
* <pre>{@code InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
|
||||
* HttpClient client = HttpClient.newBuilder()
|
||||
* .proxy(ProxySelector.of(addr))
|
||||
* .build();
|
||||
* CompletableFuture<WebSocket> ws = client.newWebSocketBuilder()
|
||||
* .buildAsync(URI.create("ws://websocket.example.com"), listener); }</pre>
|
||||
*
|
||||
* @implSpec The default implementation of this method throws
|
||||
* {@code UnsupportedOperationException}. Clients obtained through
|
||||
* {@link HttpClient#newHttpClient()} or {@link HttpClient#newBuilder()}
|
||||
* return a {@code WebSocket} builder.
|
||||
*
|
||||
* @implNote Both builder and {@code WebSocket}s created with it operate in
|
||||
* a non-blocking fashion. That is, their methods do not block before
|
||||
* returning a {@code CompletableFuture}. Asynchronous tasks are executed in
|
||||
* this {@code HttpClient}'s executor.
|
||||
*
|
||||
* <p> When a {@code CompletionStage} returned from
|
||||
* {@link WebSocket.Listener#onClose Listener.onClose} completes,
|
||||
* the {@code WebSocket} will send a Close message that has the same code
|
||||
* the received message has and an empty reason.
|
||||
*
|
||||
* @return a {@code WebSocket.Builder}
|
||||
* @throws UnsupportedOperationException
|
||||
* if this {@code HttpClient} does not provide WebSocket support
|
||||
*/
|
||||
public WebSocket.Builder newWebSocketBuilder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
168
src/java.net.http/share/classes/java/net/http/HttpHeaders.java
Normal file
168
src/java.net.http/share/classes/java/net/http/HttpHeaders.java
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.http;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A read-only view of a set of HTTP headers.
|
||||
*
|
||||
* <p> An {@code HttpHeaders} is not created directly, but rather returned from
|
||||
* an {@link HttpResponse HttpResponse}. Specific HTTP headers can be set for
|
||||
* {@linkplain HttpRequest requests} through the one of the request builder's
|
||||
* {@link HttpRequest.Builder#header(String, String) headers} methods.
|
||||
*
|
||||
* <p> The methods of this class ( that accept a String header name ), and the
|
||||
* Map returned by the {@link #map() map} method, operate without regard to
|
||||
* case when retrieving the header value.
|
||||
*
|
||||
* <p> {@code HttpHeaders} instances are immutable.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public abstract class HttpHeaders {
|
||||
|
||||
/**
|
||||
* Creates an HttpHeaders.
|
||||
*/
|
||||
protected HttpHeaders() {}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the first value of the given named
|
||||
* (and possibly multi-valued) header. If the header is not present, then
|
||||
* the returned {@code Optional} is empty.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes
|
||||
* {@code allValues(name).stream().findFirst()}
|
||||
*
|
||||
* @param name the header name
|
||||
* @return an {@code Optional<String>} for the first named value
|
||||
*/
|
||||
public Optional<String> firstValue(String name) {
|
||||
return allValues(name).stream().findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link OptionalLong} containing the first value of the
|
||||
* named header field. If the header is not present, then the Optional is
|
||||
* empty. If the header is present but contains a value that does not parse
|
||||
* as a {@code Long} value, then an exception is thrown.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes
|
||||
* {@code allValues(name).stream().mapToLong(Long::valueOf).findFirst()}
|
||||
*
|
||||
* @param name the header name
|
||||
* @return an {@code OptionalLong}
|
||||
* @throws NumberFormatException if a value is found, but does not parse as
|
||||
* a Long
|
||||
*/
|
||||
public OptionalLong firstValueAsLong(String name) {
|
||||
return allValues(name).stream().mapToLong(Long::valueOf).findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable List of all of the values of the given named
|
||||
* header. Always returns a List, which may be empty if the header is not
|
||||
* present.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes, among other things, the
|
||||
* {@code map().get(name)} to retrieve the list of header values.
|
||||
*
|
||||
* @param name the header name
|
||||
* @return a List of String values
|
||||
*/
|
||||
public List<String> allValues(String name) {
|
||||
requireNonNull(name);
|
||||
List<String> values = map().get(name);
|
||||
// Making unmodifiable list out of empty in order to make a list which
|
||||
// throws UOE unconditionally
|
||||
return values != null ? values : unmodifiableList(emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable multi Map view of this HttpHeaders.
|
||||
*
|
||||
* @return the Map
|
||||
*/
|
||||
public abstract Map<String, List<String>> map();
|
||||
|
||||
/**
|
||||
* Tests this HTTP headers instance for equality with the given object.
|
||||
*
|
||||
* <p> If the given object is not an {@code HttpHeaders} then this
|
||||
* method returns {@code false}. Two HTTP headers are equal if each
|
||||
* of their corresponding {@linkplain #map() maps} are equal.
|
||||
*
|
||||
* <p> This method satisfies the general contract of the {@link
|
||||
* Object#equals(Object) Object.equals} method.
|
||||
*
|
||||
* @param obj the object to which this object is to be compared
|
||||
* @return {@code true} if, and only if, the given object is an {@code
|
||||
* HttpHeaders} that is equal to this HTTP headers
|
||||
*/
|
||||
public final boolean equals(Object obj) {
|
||||
if (!(obj instanceof HttpHeaders))
|
||||
return false;
|
||||
HttpHeaders that = (HttpHeaders)obj;
|
||||
return this.map().equals(that.map());
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a hash code for this HTTP headers instance.
|
||||
*
|
||||
* <p> The hash code is based upon the components of the HTTP headers
|
||||
* {@link #map() map}, and satisfies the general contract of the
|
||||
* {@link Object#hashCode Object.hashCode} method.
|
||||
*
|
||||
* @return the hash-code value for this HTTP headers
|
||||
*/
|
||||
public final int hashCode() {
|
||||
return map().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this HTTP headers as a string.
|
||||
*
|
||||
* @return a string describing the HTTP headers
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(super.toString()).append(" { ");
|
||||
sb.append(map());
|
||||
sb.append(" }");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
650
src/java.net.http/share/classes/java/net/http/HttpRequest.java
Normal file
650
src/java.net.http/share/classes/java/net/http/HttpRequest.java
Normal file
|
@ -0,0 +1,650 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.http;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Flow;
|
||||
import java.util.function.Supplier;
|
||||
import jdk.internal.net.http.HttpRequestBuilderImpl;
|
||||
import jdk.internal.net.http.RequestPublishers;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* An HTTP request.
|
||||
*
|
||||
* <p> An {@code HttpRequest} instance is built through an {@code HttpRequest}
|
||||
* {@linkplain HttpRequest.Builder builder}. An {@code HttpRequest} builder
|
||||
* is obtained from one of the {@link HttpRequest#newBuilder(URI) newBuilder}
|
||||
* methods. A request's {@link URI}, headers, and body can be set. Request
|
||||
* bodies are provided through a {@link BodyPublisher BodyPublisher} supplied
|
||||
* to one of the {@link Builder#POST(BodyPublisher) POST},
|
||||
* {@link Builder#PUT(BodyPublisher) PUT} or
|
||||
* {@link Builder#method(String,BodyPublisher) method} methods.
|
||||
* Once all required parameters have been set in the builder, {@link
|
||||
* Builder#build() build} will return the {@code HttpRequest}. Builders can be
|
||||
* copied and modified many times in order to build multiple related requests
|
||||
* that differ in some parameters.
|
||||
*
|
||||
* <p> The following is an example of a GET request that prints the response
|
||||
* body as a String:
|
||||
*
|
||||
* <pre>{@code HttpClient client = HttpClient.newHttpClient();
|
||||
* HttpRequest request = HttpRequest.newBuilder()
|
||||
* .uri(URI.create("http://foo.com/"))
|
||||
* .build();
|
||||
* client.sendAsync(request, BodyHandlers.ofString())
|
||||
* .thenApply(HttpResponse::body)
|
||||
* .thenAccept(System.out::println)
|
||||
* .join(); }</pre>
|
||||
*
|
||||
* <p>The class {@link BodyPublishers BodyPublishers} provides implementations
|
||||
* of many common publishers. Alternatively, a custom {@code BodyPublisher}
|
||||
* implementation can be used.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public abstract class HttpRequest {
|
||||
|
||||
/**
|
||||
* Creates an HttpRequest.
|
||||
*/
|
||||
protected HttpRequest() {}
|
||||
|
||||
/**
|
||||
* A builder of {@linkplain HttpRequest HTTP requests}.
|
||||
*
|
||||
* <p> Instances of {@code HttpRequest.Builder} are created by calling {@link
|
||||
* HttpRequest#newBuilder(URI)} or {@link HttpRequest#newBuilder()}.
|
||||
*
|
||||
* <p> Each of the setter methods modifies the state of the builder
|
||||
* and returns the same instance. The methods are not synchronized and
|
||||
* should not be called from multiple threads without external
|
||||
* synchronization. The {@link #build() build} method returns a new
|
||||
* {@code HttpRequest} each time it is invoked. Once built an {@code
|
||||
* HttpRequest} is immutable, and can be sent multiple times.
|
||||
*
|
||||
* <p> Note, that not all request headers may be set by user code. Some are
|
||||
* restricted for security reasons and others such as the headers relating
|
||||
* to authentication, redirection and cookie management may be managed by
|
||||
* specific APIs rather than through directly user set headers.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public interface Builder {
|
||||
|
||||
/**
|
||||
* Sets this {@code HttpRequest}'s request {@code URI}.
|
||||
*
|
||||
* @param uri the request URI
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if the {@code URI} scheme is not
|
||||
* supported
|
||||
*/
|
||||
public Builder uri(URI uri);
|
||||
|
||||
/**
|
||||
* Requests the server to acknowledge the request before sending the
|
||||
* body. This is disabled by default. If enabled, the server is
|
||||
* requested to send an error response or a {@code 100 Continue}
|
||||
* response before the client sends the request body. This means the
|
||||
* request publisher for the request will not be invoked until this
|
||||
* interim response is received.
|
||||
*
|
||||
* @param enable {@code true} if Expect continue to be sent
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder expectContinue(boolean enable);
|
||||
|
||||
/**
|
||||
* Sets the preferred {@link HttpClient.Version} for this request.
|
||||
*
|
||||
* <p> The corresponding {@link HttpResponse} should be checked for the
|
||||
* version that was actually used. If the version is not set in a
|
||||
* request, then the version requested will be that of the sending
|
||||
* {@link HttpClient}.
|
||||
*
|
||||
* @param version the HTTP protocol version requested
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder version(HttpClient.Version version);
|
||||
|
||||
/**
|
||||
* Adds the given name value pair to the set of headers for this request.
|
||||
* The given value is added to the list of values for that name.
|
||||
*
|
||||
* @implNote An implementation may choose to restrict some header names
|
||||
* or values, as the HTTP Client may determine their value itself.
|
||||
* For example, "Content-Length", which will be determined by
|
||||
* the request Publisher. In such a case, an implementation of
|
||||
* {@code HttpRequest.Builder} may choose to throw an
|
||||
* {@code IllegalArgumentException} if such a header is passed
|
||||
* to the builder.
|
||||
*
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if the header name or value is not
|
||||
* valid, see <a href="https://tools.ietf.org/html/rfc7230#section-3.2">
|
||||
* RFC 7230 section-3.2</a>, or the header name or value is restricted
|
||||
* by the implementation.
|
||||
*/
|
||||
public Builder header(String name, String value);
|
||||
|
||||
/**
|
||||
* Adds the given name value pairs to the set of headers for this
|
||||
* request. The supplied {@code String} instances must alternate as
|
||||
* header names and header values.
|
||||
* To add several values to the same name then the same name must
|
||||
* be supplied with each new value.
|
||||
*
|
||||
* @param headers the list of name value pairs
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if there are an odd number of
|
||||
* parameters, or if a header name or value is not valid, see
|
||||
* <a href="https://tools.ietf.org/html/rfc7230#section-3.2">
|
||||
* RFC 7230 section-3.2</a>, or a header name or value is
|
||||
* {@linkplain #header(String, String) restricted} by the
|
||||
* implementation.
|
||||
*/
|
||||
public Builder headers(String... headers);
|
||||
|
||||
/**
|
||||
* Sets a timeout for this request. If the response is not received
|
||||
* within the specified timeout then an {@link HttpTimeoutException} is
|
||||
* thrown from {@link HttpClient#send(java.net.http.HttpRequest,
|
||||
* java.net.http.HttpResponse.BodyHandler) HttpClient::send} or
|
||||
* {@link HttpClient#sendAsync(java.net.http.HttpRequest,
|
||||
* java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync}
|
||||
* completes exceptionally with an {@code HttpTimeoutException}. The effect
|
||||
* of not setting a timeout is the same as setting an infinite Duration, ie.
|
||||
* block forever.
|
||||
*
|
||||
* @param duration the timeout duration
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if the duration is non-positive
|
||||
*/
|
||||
public abstract Builder timeout(Duration duration);
|
||||
|
||||
/**
|
||||
* Sets the given name value pair to the set of headers for this
|
||||
* request. This overwrites any previously set values for name.
|
||||
*
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if the header name or value is not valid,
|
||||
* see <a href="https://tools.ietf.org/html/rfc7230#section-3.2">
|
||||
* RFC 7230 section-3.2</a>, or the header name or value is
|
||||
* {@linkplain #header(String, String) restricted} by the
|
||||
* implementation.
|
||||
*/
|
||||
public Builder setHeader(String name, String value);
|
||||
|
||||
/**
|
||||
* Sets the request method of this builder to GET.
|
||||
* This is the default.
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder GET();
|
||||
|
||||
/**
|
||||
* Sets the request method of this builder to POST and sets its
|
||||
* request body publisher to the given value.
|
||||
*
|
||||
* @param bodyPublisher the body publisher
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder POST(BodyPublisher bodyPublisher);
|
||||
|
||||
/**
|
||||
* Sets the request method of this builder to PUT and sets its
|
||||
* request body publisher to the given value.
|
||||
*
|
||||
* @param bodyPublisher the body publisher
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder PUT(BodyPublisher bodyPublisher);
|
||||
|
||||
/**
|
||||
* Sets the request method of this builder to DELETE.
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
public Builder DELETE();
|
||||
|
||||
/**
|
||||
* Sets the request method and request body of this builder to the
|
||||
* given values.
|
||||
*
|
||||
* @apiNote The {@link BodyPublishers#noBody() noBody} request
|
||||
* body publisher can be used where no request body is required or
|
||||
* appropriate. Whether a method is restricted, or not, is
|
||||
* implementation specific. For example, some implementations may choose
|
||||
* to restrict the {@code CONNECT} method.
|
||||
*
|
||||
* @param method the method to use
|
||||
* @param bodyPublisher the body publisher
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if the method name is not
|
||||
* valid, see <a href="https://tools.ietf.org/html/rfc7230#section-3.1.1">
|
||||
* RFC 7230 section-3.1.1</a>, or the method is restricted by the
|
||||
* implementation.
|
||||
*/
|
||||
public Builder method(String method, BodyPublisher bodyPublisher);
|
||||
|
||||
/**
|
||||
* Builds and returns an {@link HttpRequest}.
|
||||
*
|
||||
* @return a new {@code HttpRequest}
|
||||
* @throws IllegalStateException if a URI has not been set
|
||||
*/
|
||||
public HttpRequest build();
|
||||
|
||||
/**
|
||||
* Returns an exact duplicate copy of this {@code Builder} based on
|
||||
* current state. The new builder can then be modified independently of
|
||||
* this builder.
|
||||
*
|
||||
* @return an exact copy of this builder
|
||||
*/
|
||||
public Builder copy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@code HttpRequest} builder with the given URI.
|
||||
*
|
||||
* @param uri the request URI
|
||||
* @return a new request builder
|
||||
* @throws IllegalArgumentException if the URI scheme is not supported.
|
||||
*/
|
||||
public static HttpRequest.Builder newBuilder(URI uri) {
|
||||
return new HttpRequestBuilderImpl(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@code HttpRequest} builder.
|
||||
*
|
||||
* @return a new request builder
|
||||
*/
|
||||
public static HttpRequest.Builder newBuilder() {
|
||||
return new HttpRequestBuilderImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing the {@link BodyPublisher} set on
|
||||
* this request. If no {@code BodyPublisher} was set in the requests's
|
||||
* builder, then the {@code Optional} is empty.
|
||||
*
|
||||
* @return an {@code Optional} containing this request's {@code BodyPublisher}
|
||||
*/
|
||||
public abstract Optional<BodyPublisher> bodyPublisher();
|
||||
|
||||
/**
|
||||
* Returns the request method for this request. If not set explicitly,
|
||||
* the default method for any request is "GET".
|
||||
*
|
||||
* @return this request's method
|
||||
*/
|
||||
public abstract String method();
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing this request's timeout duration.
|
||||
* If the timeout duration was not set in the request's builder, then the
|
||||
* {@code Optional} is empty.
|
||||
*
|
||||
* @return an {@code Optional} containing this request's timeout duration
|
||||
*/
|
||||
public abstract Optional<Duration> timeout();
|
||||
|
||||
/**
|
||||
* Returns this request's {@linkplain HttpRequest.Builder#expectContinue(boolean)
|
||||
* expect continue} setting.
|
||||
*
|
||||
* @return this request's expect continue setting
|
||||
*/
|
||||
public abstract boolean expectContinue();
|
||||
|
||||
/**
|
||||
* Returns this request's {@code URI}.
|
||||
*
|
||||
* @return this request's URI
|
||||
*/
|
||||
public abstract URI uri();
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing the HTTP protocol version that
|
||||
* will be requested for this {@code HttpRequest}. If the version was not
|
||||
* set in the request's builder, then the {@code Optional} is empty.
|
||||
* In that case, the version requested will be that of the sending
|
||||
* {@link HttpClient}. The corresponding {@link HttpResponse} should be
|
||||
* queried to determine the version that was actually used.
|
||||
*
|
||||
* @return HTTP protocol version
|
||||
*/
|
||||
public abstract Optional<HttpClient.Version> version();
|
||||
|
||||
/**
|
||||
* The (user-accessible) request headers that this request was (or will be)
|
||||
* sent with.
|
||||
*
|
||||
* @return this request's HttpHeaders
|
||||
*/
|
||||
public abstract HttpHeaders headers();
|
||||
|
||||
/**
|
||||
* Tests this HTTP request instance for equality with the given object.
|
||||
*
|
||||
* <p> If the given object is not an {@code HttpRequest} then this
|
||||
* method returns {@code false}. Two HTTP requests are equal if their URI,
|
||||
* method, and headers fields are all equal.
|
||||
*
|
||||
* <p> This method satisfies the general contract of the {@link
|
||||
* Object#equals(Object) Object.equals} method.
|
||||
*
|
||||
* @param obj the object to which this object is to be compared
|
||||
* @return {@code true} if, and only if, the given object is an {@code
|
||||
* HttpRequest} that is equal to this HTTP request
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if (! (obj instanceof HttpRequest))
|
||||
return false;
|
||||
HttpRequest that = (HttpRequest)obj;
|
||||
if (!that.method().equals(this.method()))
|
||||
return false;
|
||||
if (!that.uri().equals(this.uri()))
|
||||
return false;
|
||||
if (!that.headers().equals(this.headers()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a hash code for this HTTP request instance.
|
||||
*
|
||||
* <p> The hash code is based upon the HTTP request's URI, method, and
|
||||
* header components, and satisfies the general contract of the
|
||||
* {@link Object#hashCode Object.hashCode} method.
|
||||
*
|
||||
* @return the hash-code value for this HTTP request
|
||||
*/
|
||||
public final int hashCode() {
|
||||
return method().hashCode()
|
||||
+ uri().hashCode()
|
||||
+ headers().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code BodyPublisher} converts high-level Java objects into a flow of
|
||||
* byte buffers suitable for sending as a request body. The class
|
||||
* {@link BodyPublishers BodyPublishers} provides implementations of many
|
||||
* common publishers.
|
||||
*
|
||||
* <p> The {@code BodyPublisher} interface extends {@link Flow.Publisher
|
||||
* Flow.Publisher<ByteBuffer>}, which means that a {@code BodyPublisher}
|
||||
* acts as a publisher of {@linkplain ByteBuffer byte buffers}.
|
||||
*
|
||||
* <p> When sending a request that contains a body, the HTTP Client
|
||||
* subscribes to the request's {@code BodyPublisher} in order to receive the
|
||||
* flow of outgoing request body data. The normal semantics of {@link
|
||||
* Flow.Subscriber} and {@link Flow.Publisher} are implemented by the HTTP
|
||||
* Client and are expected from {@code BodyPublisher} implementations. Each
|
||||
* outgoing request results in one HTTP Client {@code Subscriber}
|
||||
* subscribing to the {@code BodyPublisher} in order to provide the sequence
|
||||
* of byte buffers containing the request body. Instances of {@code
|
||||
* ByteBuffer} published by the publisher must be allocated by the
|
||||
* publisher, and must not be accessed after being published to the HTTP
|
||||
* Client. These subscriptions complete normally when the request body is
|
||||
* fully sent, and can be canceled or terminated early through error. If a
|
||||
* request needs to be resent for any reason, then a new subscription is
|
||||
* created which is expected to generate the same data as before.
|
||||
*
|
||||
* <p> A {@code BodyPublisher} that reports a {@linkplain #contentLength()
|
||||
* content length} of {@code 0} may not be subscribed to by the HTTP Client,
|
||||
* as it has effectively no data to publish.
|
||||
*
|
||||
* @see BodyPublishers
|
||||
* @since 11
|
||||
*/
|
||||
public interface BodyPublisher extends Flow.Publisher<ByteBuffer> {
|
||||
|
||||
/**
|
||||
* Returns the content length for this request body. May be zero
|
||||
* if no request body being sent, greater than zero for a fixed
|
||||
* length content, or less than zero for an unknown content length.
|
||||
*
|
||||
* <p> This method may be invoked before the publisher is subscribed to.
|
||||
* This method may be invoked more than once by the HTTP client
|
||||
* implementation, and MUST return the same constant value each time.
|
||||
*
|
||||
* @return the content length for this request body, if known
|
||||
*/
|
||||
long contentLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementations of {@link BodyPublisher BodyPublisher} that implement
|
||||
* various useful publishers, such as publishing the request body from a
|
||||
* String, or from a file.
|
||||
*
|
||||
* <p> The following are examples of using the predefined body publishers to
|
||||
* convert common high-level Java objects into a flow of data suitable for
|
||||
* sending as a request body:
|
||||
*
|
||||
* <pre>{@code // Request body from a String
|
||||
* HttpRequest request = HttpRequest.newBuilder()
|
||||
* .uri(URI.create("https://foo.com/"))
|
||||
* .header("Content-Type", "text/plain; charset=UTF-8")
|
||||
* .POST(BodyPublishers.ofString("some body text"))
|
||||
* .build();
|
||||
*
|
||||
* // Request body from a File
|
||||
* HttpRequest request = HttpRequest.newBuilder()
|
||||
* .uri(URI.create("https://foo.com/"))
|
||||
* .header("Content-Type", "application/json")
|
||||
* .POST(BodyPublishers.ofFile(Paths.get("file.json")))
|
||||
* .build();
|
||||
*
|
||||
* // Request body from a byte array
|
||||
* HttpRequest request = HttpRequest.newBuilder()
|
||||
* .uri(URI.create("https://foo.com/"))
|
||||
* .POST(BodyPublishers.ofByteArray(new byte[] { ... }))
|
||||
* .build(); }</pre>
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public static class BodyPublishers {
|
||||
|
||||
private BodyPublishers() { }
|
||||
|
||||
/**
|
||||
* Returns a request body publisher whose body is retrieved from the
|
||||
* given {@code Flow.Publisher}. The returned request body publisher
|
||||
* has an unknown content length.
|
||||
*
|
||||
* @apiNote This method can be used as an adapter between {@code
|
||||
* BodyPublisher} and {@code Flow.Publisher}, where the amount of
|
||||
* request body that the publisher will publish is unknown.
|
||||
*
|
||||
* @param publisher the publisher responsible for publishing the body
|
||||
* @return a BodyPublisher
|
||||
*/
|
||||
public static BodyPublisher
|
||||
fromPublisher(Flow.Publisher<? extends ByteBuffer> publisher) {
|
||||
return new RequestPublishers.PublisherAdapter(publisher, -1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request body publisher whose body is retrieved from the
|
||||
* given {@code Flow.Publisher}. The returned request body publisher
|
||||
* has the given content length.
|
||||
*
|
||||
* <p> The given {@code contentLength} is a positive number, that
|
||||
* represents the exact amount of bytes the {@code publisher} must
|
||||
* publish.
|
||||
*
|
||||
* @apiNote This method can be used as an adapter between {@code
|
||||
* BodyPublisher} and {@code Flow.Publisher}, where the amount of
|
||||
* request body that the publisher will publish is known.
|
||||
*
|
||||
* @param publisher the publisher responsible for publishing the body
|
||||
* @param contentLength a positive number representing the exact
|
||||
* amount of bytes the publisher will publish
|
||||
* @throws IllegalArgumentException if the content length is
|
||||
* non-positive
|
||||
* @return a BodyPublisher
|
||||
*/
|
||||
public static BodyPublisher
|
||||
fromPublisher(Flow.Publisher<? extends ByteBuffer> publisher,
|
||||
long contentLength) {
|
||||
if (contentLength < 1)
|
||||
throw new IllegalArgumentException("non-positive contentLength: "
|
||||
+ contentLength);
|
||||
return new RequestPublishers.PublisherAdapter(publisher, contentLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request body publisher whose body is the given {@code
|
||||
* String}, converted using the {@link StandardCharsets#UTF_8 UTF_8}
|
||||
* character set.
|
||||
*
|
||||
* @param body the String containing the body
|
||||
* @return a BodyPublisher
|
||||
*/
|
||||
public static BodyPublisher ofString(String body) {
|
||||
return ofString(body, UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request body publisher whose body is the given {@code
|
||||
* String}, converted using the given character set.
|
||||
*
|
||||
* @param s the String containing the body
|
||||
* @param charset the character set to convert the string to bytes
|
||||
* @return a BodyPublisher
|
||||
*/
|
||||
public static BodyPublisher ofString(String s, Charset charset) {
|
||||
return new RequestPublishers.StringPublisher(s, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* A request body publisher that reads its data from an {@link
|
||||
* InputStream}. A {@link Supplier} of {@code InputStream} is used in
|
||||
* case the request needs to be repeated, as the content is not buffered.
|
||||
* The {@code Supplier} may return {@code null} on subsequent attempts,
|
||||
* in which case the request fails.
|
||||
*
|
||||
* @param streamSupplier a Supplier of open InputStreams
|
||||
* @return a BodyPublisher
|
||||
*/
|
||||
// TODO (spec): specify that the stream will be closed
|
||||
public static BodyPublisher ofInputStream(Supplier<? extends InputStream> streamSupplier) {
|
||||
return new RequestPublishers.InputStreamPublisher(streamSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request body publisher whose body is the given byte array.
|
||||
*
|
||||
* @param buf the byte array containing the body
|
||||
* @return a BodyPublisher
|
||||
*/
|
||||
public static BodyPublisher ofByteArray(byte[] buf) {
|
||||
return new RequestPublishers.ByteArrayPublisher(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a request body publisher whose body is the content of the
|
||||
* given byte array of {@code length} bytes starting from the specified
|
||||
* {@code offset}.
|
||||
*
|
||||
* @param buf the byte array containing the body
|
||||
* @param offset the offset of the first byte
|
||||
* @param length the number of bytes to use
|
||||
* @return a BodyPublisher
|
||||
* @throws IndexOutOfBoundsException if the sub-range is defined to be
|
||||
* out-of-bounds
|
||||
*/
|
||||
public static BodyPublisher ofByteArray(byte[] buf, int offset, int length) {
|
||||
Objects.checkFromIndexSize(offset, length, buf.length);
|
||||
return new RequestPublishers.ByteArrayPublisher(buf, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* A request body publisher that takes data from the contents of a File.
|
||||
*
|
||||
* <p> Security manager permission checks are performed in this factory
|
||||
* method, when the {@code BodyPublisher} is created. Care must be taken
|
||||
* that the {@code BodyPublisher} is not shared with untrusted code.
|
||||
*
|
||||
* @param path the path to the file containing the body
|
||||
* @return a BodyPublisher
|
||||
* @throws java.io.FileNotFoundException if the path is not found
|
||||
* @throws SecurityException if a security manager has been installed
|
||||
* and it denies {@link SecurityManager#checkRead(String)
|
||||
* read access} to the given file
|
||||
*/
|
||||
public static BodyPublisher ofFile(Path path) throws FileNotFoundException {
|
||||
Objects.requireNonNull(path);
|
||||
return RequestPublishers.FilePublisher.create(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* A request body publisher that takes data from an {@code Iterable}
|
||||
* of byte arrays. An {@link Iterable} is provided which supplies
|
||||
* {@link Iterator} instances. Each attempt to send the request results
|
||||
* in one invocation of the {@code Iterable}.
|
||||
*
|
||||
* @param iter an Iterable of byte arrays
|
||||
* @return a BodyPublisher
|
||||
*/
|
||||
public static BodyPublisher ofByteArrays(Iterable<byte[]> iter) {
|
||||
return new RequestPublishers.IterablePublisher(iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* A request body publisher which sends no request body.
|
||||
*
|
||||
* @return a BodyPublisher which completes immediately and sends
|
||||
* no request body.
|
||||
*/
|
||||
public static BodyPublisher noBody() {
|
||||
return new RequestPublishers.EmptyPublisher();
|
||||
}
|
||||
}
|
||||
}
|
1315
src/java.net.http/share/classes/java/net/http/HttpResponse.java
Normal file
1315
src/java.net.http/share/classes/java/net/http/HttpResponse.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Thrown when a response is not received within a specified time period.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public class HttpTimeoutException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 981344271622632951L;
|
||||
|
||||
/**
|
||||
* Constructs an {@code HttpTimeoutException} with the given detail message.
|
||||
*
|
||||
* @param message
|
||||
* The detail message; can be {@code null}
|
||||
*/
|
||||
public HttpTimeoutException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
771
src/java.net.http/share/classes/java/net/http/WebSocket.java
Normal file
771
src/java.net.http/share/classes/java/net/http/WebSocket.java
Normal file
|
@ -0,0 +1,771 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
/**
|
||||
* A WebSocket Client.
|
||||
*
|
||||
* <p> {@code WebSocket} instances can be created via {@link WebSocket.Builder}.
|
||||
*
|
||||
* <p> WebSocket has an input and an output sides. These sides are independent
|
||||
* from each other. A side can either be open or closed. Once closed, the side
|
||||
* remains closed. WebSocket messages are sent through a {@code WebSocket} and
|
||||
* received through a {@code WebSocket.Listener} associated with it. Messages
|
||||
* can be sent until the WebSocket's output is closed, and received until the
|
||||
* WebSocket's input is closed.
|
||||
*
|
||||
* <p> A send method is any of the {@code sendText}, {@code sendBinary},
|
||||
* {@code sendPing}, {@code sendPong} and {@code sendClose} methods of
|
||||
* {@code WebSocket}. A send method initiates a send operation and returns a
|
||||
* {@code CompletableFuture} which completes once the operation has completed.
|
||||
* If the {@code CompletableFuture} completes normally the operation is
|
||||
* considered succeeded. If the {@code CompletableFuture} completes
|
||||
* exceptionally, the operation is considered failed. An operation that has been
|
||||
* initiated but not yet completed is considered pending.
|
||||
*
|
||||
* <p> A receive method is any of the {@code onText}, {@code onBinary},
|
||||
* {@code onPing}, {@code onPong} and {@code onClose} methods of
|
||||
* {@code Listener}. A receive method initiates a receive operation and returns
|
||||
* a {@code CompletionStage} which completes once the operation has completed.
|
||||
*
|
||||
* <p> A WebSocket maintains an <a id="counter">internal counter</a>.
|
||||
* This counter's value is a number of times the WebSocket has yet to invoke a
|
||||
* receive method. While this counter is zero the WebSocket does not invoke
|
||||
* receive methods. The counter is incremented by {@code n} when {@code
|
||||
* request(n)} is called. The counter is decremented by one when the WebSocket
|
||||
* invokes a receive method. {@code onOpen} and {@code onError} are not receive
|
||||
* methods. WebSocket invokes {@code onOpen} prior to any other methods on the
|
||||
* listener. WebSocket invokes {@code onOpen} at most once. WebSocket may invoke
|
||||
* {@code onError} at any given time. If the WebSocket invokes {@code onError}
|
||||
* or {@code onClose}, then no further listener's methods will be invoked, no
|
||||
* matter the value of the counter. For a newly built WebSocket the counter is
|
||||
* zero. A WebSocket invokes methods on the listener in a thread-safe manner.
|
||||
*
|
||||
* <p> Unless otherwise stated, {@code null} arguments will cause methods
|
||||
* of {@code WebSocket} to throw {@code NullPointerException}, similarly,
|
||||
* {@code WebSocket} will not pass {@code null} arguments to methods of
|
||||
* {@code Listener}. The state of a WebSocket is not changed by the invocations
|
||||
* that throw or return a {@code CompletableFuture} that completes with one of
|
||||
* the {@code NullPointerException}, {@code IllegalArgumentException},
|
||||
* {@code IllegalStateException} exceptions.
|
||||
*
|
||||
* <p> {@code WebSocket} handles received Ping and Close messages automatically
|
||||
* (as per the WebSocket Protocol) by replying with Pong and Close messages. If
|
||||
* the listener receives Ping or Close messages, no mandatory actions from the
|
||||
* listener are required.
|
||||
*
|
||||
* @apiNote The relationship between a WebSocket and the associated Listener is
|
||||
* analogous to that of a Subscription and the associated Subscriber of type
|
||||
* {@link java.util.concurrent.Flow}.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public interface WebSocket {
|
||||
|
||||
/**
|
||||
* The WebSocket Close message status code (<code>{@value}</code>),
|
||||
* indicating normal closure, meaning that the purpose for which the
|
||||
* connection was established has been fulfilled.
|
||||
*
|
||||
* @see #sendClose(int, String)
|
||||
* @see Listener#onClose(WebSocket, int, String)
|
||||
*/
|
||||
int NORMAL_CLOSURE = 1000;
|
||||
|
||||
/**
|
||||
* A builder of {@linkplain WebSocket WebSocket Clients}.
|
||||
*
|
||||
* <p> A builder can be created by invoking the
|
||||
* {@link HttpClient#newWebSocketBuilder HttpClient.newWebSocketBuilder}
|
||||
* method. The intermediate (setter-like) methods change the state of the
|
||||
* builder and return the same builder they have been invoked on. If an
|
||||
* intermediate method is not invoked, an appropriate default value (or
|
||||
* behavior) will be assumed. A {@code Builder} is not safe for use by
|
||||
* multiple threads without external synchronization.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
/**
|
||||
* Adds the given name-value pair to the list of additional HTTP headers
|
||||
* sent during the opening handshake.
|
||||
*
|
||||
* <p> Headers defined in the
|
||||
* <a href="https://tools.ietf.org/html/rfc6455#section-11.3">WebSocket
|
||||
* Protocol</a> are illegal. If this method is not invoked, no
|
||||
* additional HTTP headers will be sent.
|
||||
*
|
||||
* @param name
|
||||
* the header name
|
||||
* @param value
|
||||
* the header value
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
Builder header(String name, String value);
|
||||
|
||||
/**
|
||||
* Sets a timeout for establishing a WebSocket connection.
|
||||
*
|
||||
* <p> If the connection is not established within the specified
|
||||
* duration then building of the {@code WebSocket} will fail with
|
||||
* {@link HttpTimeoutException}. If this method is not invoked then the
|
||||
* infinite timeout is assumed.
|
||||
*
|
||||
* @param timeout
|
||||
* the timeout, non-{@linkplain Duration#isNegative() negative},
|
||||
* non-{@linkplain Duration#ZERO ZERO}
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
Builder connectTimeout(Duration timeout);
|
||||
|
||||
/**
|
||||
* Sets a request for the given subprotocols.
|
||||
*
|
||||
* <p> After the {@code WebSocket} has been built, the actual
|
||||
* subprotocol can be queried via
|
||||
* {@link WebSocket#getSubprotocol WebSocket.getSubprotocol()}.
|
||||
*
|
||||
* <p> Subprotocols are specified in the order of preference. The most
|
||||
* preferred subprotocol is specified first. If there are any additional
|
||||
* subprotocols they are enumerated from the most preferred to the least
|
||||
* preferred.
|
||||
*
|
||||
* <p> Subprotocols not conforming to the syntax of subprotocol
|
||||
* identifiers are illegal. If this method is not invoked then no
|
||||
* subprotocols will be requested.
|
||||
*
|
||||
* @param mostPreferred
|
||||
* the most preferred subprotocol
|
||||
* @param lesserPreferred
|
||||
* the lesser preferred subprotocols
|
||||
*
|
||||
* @return this builder
|
||||
*/
|
||||
Builder subprotocols(String mostPreferred, String... lesserPreferred);
|
||||
|
||||
/**
|
||||
* Builds a {@link WebSocket} connected to the given {@code URI} and
|
||||
* associated with the given {@code Listener}.
|
||||
*
|
||||
* <p> Returns a {@code CompletableFuture} which will either complete
|
||||
* normally with the resulting {@code WebSocket} or complete
|
||||
* exceptionally with one of the following errors:
|
||||
* <ul>
|
||||
* <li> {@link IOException} -
|
||||
* if an I/O error occurs
|
||||
* <li> {@link WebSocketHandshakeException} -
|
||||
* if the opening handshake fails
|
||||
* <li> {@link HttpTimeoutException} -
|
||||
* if the opening handshake does not complete within
|
||||
* the timeout
|
||||
* <li> {@link InterruptedException} -
|
||||
* if the operation is interrupted
|
||||
* <li> {@link SecurityException} -
|
||||
* if a security manager has been installed and it denies
|
||||
* {@link java.net.URLPermission access} to {@code uri}.
|
||||
* <a href="HttpRequest.html#securitychecks">Security checks</a>
|
||||
* contains more information relating to the security context
|
||||
* in which the the listener is invoked.
|
||||
* <li> {@link IllegalArgumentException} -
|
||||
* if any of the arguments of this builder's methods are
|
||||
* illegal
|
||||
* </ul>
|
||||
*
|
||||
* @param uri
|
||||
* the WebSocket URI
|
||||
* @param listener
|
||||
* the listener
|
||||
*
|
||||
* @return a {@code CompletableFuture} with the {@code WebSocket}
|
||||
*/
|
||||
CompletableFuture<WebSocket> buildAsync(URI uri, Listener listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* The receiving interface of {@code WebSocket}.
|
||||
*
|
||||
* <p> A {@code WebSocket} invokes methods of the associated listener
|
||||
* passing itself as an argument. When data has been received, the
|
||||
* {@code WebSocket} invokes a receive method. Methods {@code onText},
|
||||
* {@code onBinary}, {@code onPing} and {@code onPong} must return a
|
||||
* {@code CompletionStage} that completes once the message has been received
|
||||
* by the listener.
|
||||
*
|
||||
* <p> An {@code IOException} raised in {@code WebSocket} will result in an
|
||||
* invocation of {@code onError} with that exception (if the input is not
|
||||
* closed). Unless otherwise stated if the listener's method throws an
|
||||
* exception or a {@code CompletionStage} returned from a method completes
|
||||
* exceptionally, the WebSocket will invoke {@code onError} with this
|
||||
* exception.
|
||||
*
|
||||
* <p> If a listener's method returns {@code null} rather than a
|
||||
* {@code CompletionStage}, {@code WebSocket} will behave as if the listener
|
||||
* returned a {@code CompletionStage} that is already completed normally.
|
||||
*
|
||||
* @apiNote Careful attention may be required if a listener is associated
|
||||
* with more than a single {@code WebSocket}. In this case invocations
|
||||
* related to different instances of {@code WebSocket} may not be ordered
|
||||
* and may even happen concurrently.
|
||||
*
|
||||
* <p> {@code CompletionStage}s returned from the receive methods have
|
||||
* nothing to do with the
|
||||
* <a href="WebSocket.html#counter">counter of invocations</a>.
|
||||
* Namely, a {@code CompletionStage} does not have to be completed in order
|
||||
* to receive more invocations of the listener's methods.
|
||||
* Here is an example of a listener that requests invocations, one at a
|
||||
* time, until a complete message has been accumulated, then processes
|
||||
* the result, and completes the {@code CompletionStage}:
|
||||
* <pre>{@code WebSocket.Listener listener = new WebSocket.Listener() {
|
||||
*
|
||||
* List<CharSequence> parts = new ArrayList<>();
|
||||
* CompletableFuture<?> accumulatedMessage = new CompletableFuture<>();
|
||||
*
|
||||
* public CompletionStage<?> onText(WebSocket webSocket,
|
||||
* CharSequence message,
|
||||
* boolean last) {
|
||||
* parts.add(message);
|
||||
* webSocket.request(1);
|
||||
* if (last) {
|
||||
* processWholeText(parts);
|
||||
* parts = new ArrayList<>();
|
||||
* accumulatedMessage.complete(null);
|
||||
* CompletionStage<?> cf = accumulatedMessage;
|
||||
* accumulatedMessage = new CompletableFuture<>();
|
||||
* return cf;
|
||||
* }
|
||||
* return accumulatedMessage;
|
||||
* }
|
||||
* ...
|
||||
* } } </pre>
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
interface Listener {
|
||||
|
||||
/**
|
||||
* A {@code WebSocket} has been connected.
|
||||
*
|
||||
* <p> This is the initial invocation and it is made once. It is
|
||||
* typically used to make a request for more invocations.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* <pre>{@code webSocket.request(1); }</pre>
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket that has been connected
|
||||
*/
|
||||
default void onOpen(WebSocket webSocket) { webSocket.request(1); }
|
||||
|
||||
/**
|
||||
* A textual data has been received.
|
||||
*
|
||||
* <p> Return a {@code CompletionStage} which will be used by the
|
||||
* {@code WebSocket} as an indication it may reclaim the
|
||||
* {@code CharSequence}. Do not access the {@code CharSequence} after
|
||||
* this {@code CompletionStage} has completed.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* <pre>{@code webSocket.request(1);
|
||||
* return null; }</pre>
|
||||
*
|
||||
* @implNote The {@code data} is always a legal UTF-16 sequence.
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket on which the data has been received
|
||||
* @param data
|
||||
* the data
|
||||
* @param last
|
||||
* whether this invocation completes the message
|
||||
*
|
||||
* @return a {@code CompletionStage} which completes when the
|
||||
* {@code CharSequence} may be reclaimed; or {@code null} if it may be
|
||||
* reclaimed immediately
|
||||
*/
|
||||
default CompletionStage<?> onText(WebSocket webSocket,
|
||||
CharSequence data,
|
||||
boolean last) {
|
||||
webSocket.request(1);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary data has been received.
|
||||
*
|
||||
* <p> This data is located in bytes from the buffer's position to its
|
||||
* limit.
|
||||
*
|
||||
* <p> Return a {@code CompletionStage} which will be used by the
|
||||
* {@code WebSocket} as an indication it may reclaim the
|
||||
* {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
|
||||
* this {@code CompletionStage} has completed.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* <pre>{@code webSocket.request(1);
|
||||
* return null; }</pre>
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket on which the data has been received
|
||||
* @param data
|
||||
* the data
|
||||
* @param last
|
||||
* whether this invocation completes the message
|
||||
*
|
||||
* @return a {@code CompletionStage} which completes when the
|
||||
* {@code ByteBuffer} may be reclaimed; or {@code null} if it may be
|
||||
* reclaimed immediately
|
||||
*/
|
||||
default CompletionStage<?> onBinary(WebSocket webSocket,
|
||||
ByteBuffer data,
|
||||
boolean last) {
|
||||
webSocket.request(1);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Ping message has been received.
|
||||
*
|
||||
* <p> As guaranteed by the WebSocket Protocol, the message consists of
|
||||
* not more than {@code 125} bytes. These bytes are located from the
|
||||
* buffer's position to its limit.
|
||||
*
|
||||
* <p> Given that the WebSocket implementation will automatically send a
|
||||
* reciprocal pong when a ping is received, it is rarely required to
|
||||
* send a pong message explicitly when a ping is received.
|
||||
*
|
||||
* <p> Return a {@code CompletionStage} which will be used by the
|
||||
* {@code WebSocket} as a signal it may reclaim the
|
||||
* {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
|
||||
* this {@code CompletionStage} has completed.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* <pre>{@code webSocket.request(1);
|
||||
* return null; }</pre>
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket on which the message has been received
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a {@code CompletionStage} which completes when the
|
||||
* {@code ByteBuffer} may be reclaimed; or {@code null} if it may be
|
||||
* reclaimed immediately
|
||||
*/
|
||||
default CompletionStage<?> onPing(WebSocket webSocket,
|
||||
ByteBuffer message) {
|
||||
webSocket.request(1);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Pong message has been received.
|
||||
*
|
||||
* <p> As guaranteed by the WebSocket Protocol, the message consists of
|
||||
* not more than {@code 125} bytes. These bytes are located from the
|
||||
* buffer's position to its limit.
|
||||
*
|
||||
* <p> Return a {@code CompletionStage} which will be used by the
|
||||
* {@code WebSocket} as a signal it may reclaim the
|
||||
* {@code ByteBuffer}. Do not access the {@code ByteBuffer} after
|
||||
* this {@code CompletionStage} has completed.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* <pre>{@code webSocket.request(1);
|
||||
* return null; }</pre>
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket on which the message has been received
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a {@code CompletionStage} which completes when the
|
||||
* {@code ByteBuffer} may be reclaimed; or {@code null} if it may be
|
||||
* reclaimed immediately
|
||||
*/
|
||||
default CompletionStage<?> onPong(WebSocket webSocket,
|
||||
ByteBuffer message) {
|
||||
webSocket.request(1);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a Close message indicating the WebSocket's input has been
|
||||
* closed.
|
||||
*
|
||||
* <p> This is the last invocation from the specified {@code WebSocket}.
|
||||
* By the time this invocation begins the WebSocket's input will have
|
||||
* been closed.
|
||||
*
|
||||
* <p> A Close message consists of a status code and a reason for
|
||||
* closing. The status code is an integer from the range
|
||||
* {@code 1000 <= code <= 65535}. The {@code reason} is a string which
|
||||
* has a UTF-8 representation not longer than {@code 123} bytes.
|
||||
*
|
||||
* <p> If the WebSocket's output is not already closed, the
|
||||
* {@code CompletionStage} returned by this method will be used as an
|
||||
* indication that the WebSocket's output may be closed. The WebSocket
|
||||
* will close its output at the earliest of completion of the returned
|
||||
* {@code CompletionStage} or invoking either of the {@code sendClose}
|
||||
* or {@code abort} methods.
|
||||
*
|
||||
* @apiNote Returning a {@code CompletionStage} that never completes,
|
||||
* effectively disables the reciprocating closure of the output.
|
||||
*
|
||||
* <p> To specify a custom closure code or reason code the
|
||||
* {@code sendClose} method may be invoked from inside the
|
||||
* {@code onClose} invocation:
|
||||
* <pre>{@code public CompletionStage<?> onClose(WebSocket webSocket,
|
||||
* int statusCode,
|
||||
* String reason) {
|
||||
* webSocket.sendClose(CUSTOM_STATUS_CODE, CUSTOM_REASON);
|
||||
* return new CompletableFuture<Void>();
|
||||
* } } </pre>
|
||||
*
|
||||
* @implSpec The default implementation of this method returns
|
||||
* {@code null}, indicating that the output should be closed
|
||||
* immediately.
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket on which the message has been received
|
||||
* @param statusCode
|
||||
* the status code
|
||||
* @param reason
|
||||
* the reason
|
||||
*
|
||||
* @return a {@code CompletionStage} which completes when the
|
||||
* {@code WebSocket} may be closed; or {@code null} if it may be
|
||||
* closed immediately
|
||||
*/
|
||||
default CompletionStage<?> onClose(WebSocket webSocket,
|
||||
int statusCode,
|
||||
String reason) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An error has occurred.
|
||||
*
|
||||
* <p> This is the last invocation from the specified WebSocket. By the
|
||||
* time this invocation begins both the WebSocket's input and output
|
||||
* will have been closed. A WebSocket may invoke this method on the
|
||||
* associated listener at any time after it has invoked {@code onOpen},
|
||||
* regardless of whether or not any invocations have been requested from
|
||||
* the WebSocket.
|
||||
*
|
||||
* <p> If an exception is thrown from this method, resulting behavior is
|
||||
* undefined.
|
||||
*
|
||||
* @param webSocket
|
||||
* the WebSocket on which the error has occurred
|
||||
* @param error
|
||||
* the error
|
||||
*/
|
||||
default void onError(WebSocket webSocket, Throwable error) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends textual data with characters from the given character sequence.
|
||||
*
|
||||
* <p> The character sequence must not be modified until the
|
||||
* {@code CompletableFuture} returned from this method has completed.
|
||||
*
|
||||
* <p> A {@code CompletableFuture} returned from this method can
|
||||
* complete exceptionally with:
|
||||
* <ul>
|
||||
* <li> {@link IllegalStateException} -
|
||||
* if there is a pending text or binary send operation
|
||||
* or if the previous binary data does not complete the message
|
||||
* <li> {@link IOException} -
|
||||
* if an I/O error occurs, or if the output is closed
|
||||
* </ul>
|
||||
*
|
||||
* @implNote If {@code data} is a malformed UTF-16 sequence, the operation
|
||||
* will fail with {@code IOException}.
|
||||
*
|
||||
* @param data
|
||||
* the data
|
||||
* @param last
|
||||
* {@code true} if this invocation completes the message,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @return a {@code CompletableFuture} that completes, with this WebSocket,
|
||||
* when the data has been sent
|
||||
*/
|
||||
CompletableFuture<WebSocket> sendText(CharSequence data, boolean last);
|
||||
|
||||
/**
|
||||
* Sends binary data with bytes from the given buffer.
|
||||
*
|
||||
* <p> The data is located in bytes from the buffer's position to its limit.
|
||||
* Upon normal completion of a {@code CompletableFuture} returned from this
|
||||
* method the buffer will have no remaining bytes. The buffer must not be
|
||||
* accessed until after that.
|
||||
*
|
||||
* <p> The {@code CompletableFuture} returned from this method can
|
||||
* complete exceptionally with:
|
||||
* <ul>
|
||||
* <li> {@link IllegalStateException} -
|
||||
* if there is a pending text or binary send operation
|
||||
* or if the previous textual data does not complete the message
|
||||
* <li> {@link IOException} -
|
||||
* if an I/O error occurs, or if the output is closed
|
||||
* </ul>
|
||||
*
|
||||
* @param data
|
||||
* the data
|
||||
* @param last
|
||||
* {@code true} if this invocation completes the message,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @return a {@code CompletableFuture} that completes, with this WebSocket,
|
||||
* when the data has been sent
|
||||
*/
|
||||
CompletableFuture<WebSocket> sendBinary(ByteBuffer data, boolean last);
|
||||
|
||||
/**
|
||||
* Sends a Ping message with bytes from the given buffer.
|
||||
*
|
||||
* <p> The message consists of not more than {@code 125} bytes from the
|
||||
* buffer's position to its limit. Upon normal completion of a
|
||||
* {@code CompletableFuture} returned from this method the buffer will
|
||||
* have no remaining bytes. The buffer must not be accessed until after that.
|
||||
*
|
||||
* <p> The {@code CompletableFuture} returned from this method can
|
||||
* complete exceptionally with:
|
||||
* <ul>
|
||||
* <li> {@link IllegalStateException} -
|
||||
* if there is a pending ping or pong send operation
|
||||
* <li> {@link IllegalArgumentException} -
|
||||
* if the message is too long
|
||||
* <li> {@link IOException} -
|
||||
* if an I/O error occurs, or if the output is closed
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a {@code CompletableFuture} that completes, with this WebSocket,
|
||||
* when the Ping message has been sent
|
||||
*/
|
||||
CompletableFuture<WebSocket> sendPing(ByteBuffer message);
|
||||
|
||||
/**
|
||||
* Sends a Pong message with bytes from the given buffer.
|
||||
*
|
||||
* <p> The message consists of not more than {@code 125} bytes from the
|
||||
* buffer's position to its limit. Upon normal completion of a
|
||||
* {@code CompletableFuture} returned from this method the buffer will have
|
||||
* no remaining bytes. The buffer must not be accessed until after that.
|
||||
*
|
||||
* <p> Given that the WebSocket implementation will automatically send a
|
||||
* reciprocal pong when a ping is received, it is rarely required to send a
|
||||
* pong message explicitly.
|
||||
*
|
||||
* <p> The {@code CompletableFuture} returned from this method can
|
||||
* complete exceptionally with:
|
||||
* <ul>
|
||||
* <li> {@link IllegalStateException} -
|
||||
* if there is a pending ping or pong send operation
|
||||
* <li> {@link IllegalArgumentException} -
|
||||
* if the message is too long
|
||||
* <li> {@link IOException} -
|
||||
* if an I/O error occurs, or if the output is closed
|
||||
* </ul>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
*
|
||||
* @return a {@code CompletableFuture} that completes, with this WebSocket,
|
||||
* when the Pong message has been sent
|
||||
*/
|
||||
CompletableFuture<WebSocket> sendPong(ByteBuffer message);
|
||||
|
||||
/**
|
||||
* Initiates an orderly closure of this WebSocket's output by
|
||||
* sending a Close message with the given status code and the reason.
|
||||
*
|
||||
* <p> The {@code statusCode} is an integer from the range
|
||||
* {@code 1000 <= code <= 4999}. Status codes {@code 1002}, {@code 1003},
|
||||
* {@code 1006}, {@code 1007}, {@code 1009}, {@code 1010}, {@code 1012},
|
||||
* {@code 1013} and {@code 1015} are illegal. Behaviour in respect to other
|
||||
* status codes is implementation-specific. A legal {@code reason} is a
|
||||
* string that has a UTF-8 representation not longer than {@code 123} bytes.
|
||||
*
|
||||
* <p> A {@code CompletableFuture} returned from this method can
|
||||
* complete exceptionally with:
|
||||
* <ul>
|
||||
* <li> {@link IllegalArgumentException} -
|
||||
* if {@code statusCode} is illegal, or
|
||||
* if {@code reason} is illegal
|
||||
* <li> {@link IOException} -
|
||||
* if an I/O error occurs, or if the output is closed
|
||||
* </ul>
|
||||
*
|
||||
* <p> Unless the {@code CompletableFuture} returned from this method
|
||||
* completes with {@code IllegalArgumentException}, or the method throws
|
||||
* {@code NullPointerException}, the output will be closed.
|
||||
*
|
||||
* <p> If not already closed, the input remains open until a Close message
|
||||
* {@linkplain Listener#onClose(WebSocket, int, String) received}, or
|
||||
* {@code abort} is invoked, or an
|
||||
* {@linkplain Listener#onError(WebSocket, Throwable) error} occurs.
|
||||
*
|
||||
* @apiNote Use the provided integer constant {@link #NORMAL_CLOSURE} as a
|
||||
* status code and an empty string as a reason in a typical case:
|
||||
* <pre>{@code CompletableFuture<WebSocket> webSocket = ...
|
||||
* webSocket.thenCompose(ws -> ws.sendText("Hello, ", false))
|
||||
* .thenCompose(ws -> ws.sendText("world!", true))
|
||||
* .thenCompose(ws -> ws.sendClose(WebSocket.NORMAL_CLOSURE, ""))
|
||||
* .join(); }</pre>
|
||||
*
|
||||
* The {@code sendClose} method does not close this WebSocket's input. It
|
||||
* merely closes this WebSocket's output by sending a Close message. To
|
||||
* enforce closing the input, invoke the {@code abort} method. Here is an
|
||||
* example of an application that sends a Close message, and then starts a
|
||||
* timer. Once no data has been received within the specified timeout, the
|
||||
* timer goes off and the alarm aborts {@code WebSocket}:
|
||||
* <pre>{@code MyAlarm alarm = new MyAlarm(webSocket::abort);
|
||||
* WebSocket.Listener listener = new WebSocket.Listener() {
|
||||
*
|
||||
* public CompletionStage<?> onText(WebSocket webSocket,
|
||||
* CharSequence data,
|
||||
* boolean last) {
|
||||
* alarm.snooze();
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
* };
|
||||
* ...
|
||||
* Runnable startTimer = () -> {
|
||||
* MyTimer idleTimer = new MyTimer();
|
||||
* idleTimer.add(alarm, 30, TimeUnit.SECONDS);
|
||||
* };
|
||||
* webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "ok").thenRun(startTimer);
|
||||
* } </pre>
|
||||
*
|
||||
* @param statusCode
|
||||
* the status code
|
||||
* @param reason
|
||||
* the reason
|
||||
*
|
||||
* @return a {@code CompletableFuture} that completes, with this WebSocket,
|
||||
* when the Close message has been sent
|
||||
*/
|
||||
CompletableFuture<WebSocket> sendClose(int statusCode, String reason);
|
||||
|
||||
/**
|
||||
* Increments the counter of invocations of receive methods.
|
||||
*
|
||||
* <p> This WebSocket will invoke {@code onText}, {@code onBinary},
|
||||
* {@code onPing}, {@code onPong} or {@code onClose} methods on the
|
||||
* associated listener (i.e. receive methods) up to {@code n} more times.
|
||||
*
|
||||
* @apiNote The parameter of this method is the number of invocations being
|
||||
* requested from this WebSocket to the associated listener, not the number
|
||||
* of messages. Sometimes a message may be delivered to the listener in a
|
||||
* single invocation, but not always. For example, Ping, Pong and Close
|
||||
* messages are delivered in a single invocation of {@code onPing},
|
||||
* {@code onPong} and {@code onClose} methods respectively. However, whether
|
||||
* or not Text and Binary messages are delivered in a single invocation of
|
||||
* {@code onText} and {@code onBinary} methods depends on the boolean
|
||||
* argument ({@code last}) of these methods. If {@code last} is
|
||||
* {@code false}, then there is more to a message than has been delivered to
|
||||
* the invocation.
|
||||
*
|
||||
* <p> Here is an example of a listener that requests invocations, one at a
|
||||
* time, until a complete message has been accumulated, and then processes
|
||||
* the result:
|
||||
* <pre>{@code WebSocket.Listener listener = new WebSocket.Listener() {
|
||||
*
|
||||
* StringBuilder text = new StringBuilder();
|
||||
*
|
||||
* public CompletionStage<?> onText(WebSocket webSocket,
|
||||
* CharSequence message,
|
||||
* boolean last) {
|
||||
* text.append(message);
|
||||
* if (last) {
|
||||
* processCompleteTextMessage(text);
|
||||
* text = new StringBuilder();
|
||||
* }
|
||||
* webSocket.request(1);
|
||||
* return null;
|
||||
* }
|
||||
* ...
|
||||
* } } </pre>
|
||||
*
|
||||
* @param n
|
||||
* the number of invocations
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code n <= 0}
|
||||
*/
|
||||
void request(long n);
|
||||
|
||||
/**
|
||||
* Returns the subprotocol used by this WebSocket.
|
||||
*
|
||||
* @return the subprotocol, or an empty string if there's no subprotocol
|
||||
*/
|
||||
String getSubprotocol();
|
||||
|
||||
/**
|
||||
* Tells whether this WebSocket's output is closed.
|
||||
*
|
||||
* <p> If this method returns {@code true}, subsequent invocations will also
|
||||
* return {@code true}.
|
||||
*
|
||||
* @return {@code true} if closed, {@code false} otherwise
|
||||
*/
|
||||
boolean isOutputClosed();
|
||||
|
||||
/**
|
||||
* Tells whether this WebSocket's input is closed.
|
||||
*
|
||||
* <p> If this method returns {@code true}, subsequent invocations will also
|
||||
* return {@code true}.
|
||||
*
|
||||
* @return {@code true} if closed, {@code false} otherwise
|
||||
*/
|
||||
boolean isInputClosed();
|
||||
|
||||
/**
|
||||
* Closes this WebSocket's input and output abruptly.
|
||||
*
|
||||
* <p> When this method returns both the input and the output will have been
|
||||
* closed. Any pending send operations will fail with {@code IOException}.
|
||||
* Subsequent invocations of {@code abort} will have no effect.
|
||||
*/
|
||||
void abort();
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An exception used to signal the opening handshake failed.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public final class WebSocketHandshakeException extends IOException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient HttpResponse<?> response;
|
||||
|
||||
/**
|
||||
* Constructs a {@code WebSocketHandshakeException} with the given
|
||||
* {@code HttpResponse}.
|
||||
*
|
||||
* @param response
|
||||
* the {@code HttpResponse} that resulted in the handshake failure
|
||||
*/
|
||||
public WebSocketHandshakeException(HttpResponse<?> response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server's counterpart of the opening handshake.
|
||||
*
|
||||
* <p> The value may be unavailable ({@code null}) if this exception has
|
||||
* been serialized and then deserialized.
|
||||
*
|
||||
* @return server response
|
||||
*/
|
||||
public HttpResponse<?> getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketHandshakeException initCause(Throwable cause) {
|
||||
return (WebSocketHandshakeException) super.initCause(cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <h2>HTTP Client and WebSocket APIs</h2>
|
||||
*
|
||||
* <p> Provides high-level client interfaces to HTTP (versions 1.1 and 2) and
|
||||
* low-level client interfaces to WebSocket. The main types defined are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link java.net.http.HttpClient}</li>
|
||||
* <li>{@link java.net.http.HttpRequest}</li>
|
||||
* <li>{@link java.net.http.HttpResponse}</li>
|
||||
* <li>{@link java.net.http.WebSocket}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> The protocol-specific requirements are defined in the
|
||||
* <a href="https://tools.ietf.org/html/rfc7540">Hypertext Transfer Protocol
|
||||
* Version 2 (HTTP/2)</a>, the <a href="https://tools.ietf.org/html/rfc2616">
|
||||
* Hypertext Transfer Protocol (HTTP/1.1)</a>, and
|
||||
* <a href="https://tools.ietf.org/html/rfc6455">The WebSocket Protocol</a>.
|
||||
*
|
||||
* <p> Asynchronous tasks and dependent actions of returned {@link
|
||||
* java.util.concurrent.CompletableFuture} instances are executed on the threads
|
||||
* supplied by the client's {@link java.util.concurrent.Executor}, where
|
||||
* practical.
|
||||
*
|
||||
* <p> {@code CompletableFuture}s returned by this API will throw {@link
|
||||
* java.lang.UnsupportedOperationException} for their {@link
|
||||
* java.util.concurrent.CompletableFuture#obtrudeValue(Object) obtrudeValue}
|
||||
* and {@link java.util.concurrent.CompletableFuture#obtrudeException(Throwable)
|
||||
* obtrudeException} methods. Invoking the {@link
|
||||
* java.util.concurrent.CompletableFuture#cancel cancel} method on a {@code
|
||||
* CompletableFuture} returned by this API will not interrupt the underlying
|
||||
* operation, but may be useful to complete, exceptionally, dependent stages
|
||||
* that have not already completed.
|
||||
*
|
||||
* <p> Unless otherwise stated, {@code null} parameter values will cause methods
|
||||
* of all classes in this package to throw {@code NullPointerException}.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
package java.net.http;
|
Loading…
Add table
Add a link
Reference in a new issue