--- old/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java 2017-11-30 04:04:01.977314408 -0800 +++ new/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java 2017-11-30 04:04:01.662286869 -0800 @@ -26,20 +26,22 @@ package jdk.incubator.http; import java.io.IOException; -import java.io.UncheckedIOException; +import java.io.InputStream; import java.net.URI; -import jdk.incubator.http.ResponseProcessors.MultiFile; -import jdk.incubator.http.ResponseProcessors.MultiProcessorImpl; +import jdk.incubator.http.ResponseSubscribers.MultiSubscriberImpl; import static jdk.incubator.http.internal.common.Utils.unchecked; import static jdk.incubator.http.internal.common.Utils.charsetFrom; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; +import java.nio.channels.FileChannel; import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import java.util.Map; +import java.security.AccessControlContext; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -52,7 +54,7 @@ * Represents a response to a {@link HttpRequest}. * {@Incubating} * - *
A {@code HttpResponse} is available when the response status code and + *
A {@code HttpResponse} is available when the response status code and * headers have been received, and typically after the response body has also * been received. This depends on the response body handler provided when * sending the request. In all cases, the response body handler is invoked @@ -61,23 +63,24 @@ * *
Methods are provided in this class for accessing the response headers, * and response body. - *
- * Response handlers and processors - *
- * Response bodies are handled at two levels. Application code supplies a response - * handler ({@link BodyHandler}) which may examine the response status code - * and headers, and which then returns a {@link BodyProcessor} to actually read - * (or discard) the body and convert it into some useful Java object type. The handler - * can return one of the pre-defined processor types, or a custom processor, or - * if the body is to be discarded, it can call {@link BodyProcessor#discard(Object) - * BodyProcessor.discard()} and return a processor which discards the response body. - * Static implementations of both handlers and processors are provided in - * {@link BodyHandler BodyHandler} and {@link BodyProcessor BodyProcessor} respectively. - * In all cases, the handler functions provided are convenience implementations - * which ignore the supplied status code and - * headers and return the relevant pre-defined {@code BodyProcessor}. - *
- * See {@link BodyHandler} for example usage. + * + *
Response handlers and subscribers + * + *
Response bodies are handled at two levels. Application code supplies a + * response handler ({@link BodyHandler}) which may examine the response status + * code and headers, and which then returns a {@link BodySubscriber} to actually + * read (or discard) the body and convert it into some useful Java object type. + * The handler can return one of the pre-defined subscriber types, or a custom + * subscriber, or if the body is to be discarded it can call {@link + * BodySubscriber#discard(Object) discard} and return a subscriber which + * discards the response body. Static implementations of both handlers and + * subscribers are provided in {@linkplain BodyHandler BodyHandler} and + * {@linkplain BodySubscriber BodySubscriber} respectively. In all cases, the + * handler functions provided are convenience implementations which ignore the + * supplied status code and headers and return the relevant pre-defined {@code + * BodySubscriber}. + * + *
See {@link BodyHandler} for example usage.
*
* @param This may not be the original request provided by the caller,
+ * for example, if that request was redirected.
+ *
+ * @see #previousResponse()
*
* @return the request
*/
public abstract HttpRequest request();
/**
- * Returns the final {@link HttpRequest} that was sent on the wire for the
- * exchange ( may, or may not, be the same as the initial request ).
+ * Returns an {@code Optional} containing the previous intermediate response
+ * if one was received. An intermediate response is one that is received
+ * as a result of redirection or authentication. If no previous response
+ * was received then an empty {@code Optional} is returned.
*
- * @return the request
+ * @return an Optional containing the HttpResponse, if any.
*/
- public abstract HttpRequest finalRequest();
+ public abstract Optional If this {@code HttpResponse} was returned from an invocation of
+ * {@link #previousResponse()} then this method returns {@code null}
+ *
* @return the body
*/
public abstract T body();
@@ -161,36 +164,124 @@
*/
public abstract HttpClient.Version version();
+
+ private static String pathForSecurityCheck(Path path) {
+ return path.toFile().getPath();
+ }
+
+ /** A body handler that is further restricted by a given ACC. */
+ interface UntrustedBodyHandler
- * This is a function that takes two parameters: the response status code,
- * and the response headers, and which returns a {@link BodyProcessor}.
+ *
+ * This is a function that takes two parameters: the response status code,
+ * and the response headers, and which returns a {@linkplain BodySubscriber}.
* The function is always called just before the response body is read. Its
* implementation may examine the status code or headers and must decide,
* whether to accept the response body or discard it, and if accepting it,
* exactly how to handle it.
- *
- * Some pre-defined implementations which do not utilize the status code
+ *
+ * Some pre-defined implementations which do not utilize the status code
* or headers (meaning the body is always accepted) are defined:
*
- * These implementations return the equivalent {@link BodyProcessor}.
+ * These implementations return the equivalent {@link BodySubscriber}.
* Alternatively, the handler can be used to examine the status code
- * or headers and return different body processors as appropriate.
- *
- * Examples of handler usage
- *
- * The first example uses one of the predefined handler functions which
- * ignore the response headers and status, and always process the response
+ * or headers and return different body subscribers as appropriate.
+ *
+ * Examples of handler usage
+ *
+ * The first example uses one of the predefined handler functions which
+ * ignores the response headers and status, and always process the response
* body in the same way.
*
- * In the second example, the function returns a different processor depending
- * on the status code.
+ * and headers, this information is still accessible from the
+ * {@code HttpResponse} when it is returned.
+ *
+ * In the second example, the function returns a different subscriber
+ * depending on the status code.
* When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the file, and {@link #body()} returns a
+ * reference to its {@link Path}.
+ *
+ * @param file the filename to store the body in
+ * @param openOptions any options to use when opening/creating the file
+ * @return a response body handler
+ * @throws SecurityException If a security manager has been installed
+ * and it denies {@link SecurityManager#checkWrite(String)
+ * write access} to the file. The {@link
+ * SecurityManager#checkDelete(String) checkDelete} method is
+ * invoked to check delete access if the file is opened with
+ * the {@code DELETE_ON_CLOSE} option.
+ */
+ public static BodyHandler
- * When the {@code HttpResponse} object is returned, the body has been completely
- * written to the file, and {@link #body()} returns a reference to its
- * {@link Path}.
+ * {@link BodySubscriber BodySubscriber}{@code When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the file, and {@link #body()} returns a
+ * reference to its {@link Path}.
*
* @param file the file to store the body in
* @return a response body handler
+ * @throws SecurityException if a security manager has been installed
+ * and it denies {@link SecurityManager#checkWrite(String)
+ * write access} to the file
*/
public static BodyHandler When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the file and {@link #body()} returns a
+ * {@code Path} object for the file. The returned {@code Path} is the
* combination of the supplied directory name and the file name supplied
* by the server. If the destination directory does not exist or cannot
* be written to, then the response will fail with an {@link IOException}.
@@ -307,245 +439,355 @@
* @param directory the directory to store the file in
* @param openOptions open options
* @return a response body handler
- */
- public static BodyHandler
- * When the {@code HttpResponse} object is returned, the body has been completely
- * written to the file, and {@link #body()} returns a reference to its
- * {@link Path}.
+ * Returns a {@code BodyHandler When the {@code HttpResponse} object is returned, the response
+ * headers will have been completely read, but the body may not have
+ * been fully received yet. The {@link #body()} method returns an
+ * {@link InputStream} from which the body can be read as it is received.
+ *
+ * @apiNote See {@link BodySubscriber#asInputStream()} for more information.
*
- * @param file the filename to store the body in
- * @param openOptions any options to use when opening/creating the file
* @return a response body handler
*/
- public static BodyHandler
- * When the {@code HttpResponse} object is returned, the body has been completely
- * written to the consumer.
+ * {@link BodySubscriber BodySubscriber}{@code When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the consumer.
*
* @param consumer a Consumer to accept the response body
* @return a response body handler
*/
public static BodyHandler
- * When the {@code HttpResponse} object is returned, the body has been completely
- * written to the byte array.
+ * {@link BodySubscriber BodySubscriber}<{@code byte[]}> obtained
+ * from {@link BodySubscriber#asByteArray() BodySubscriber.asByteArray()}.
+ *
+ * When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the byte array.
*
* @return a response body handler
*/
public static BodyHandler
- * When the {@code HttpResponse} object is returned, the body has been completely
- * written to the string.
+ *
+ * When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the string.
*
* @return a response body handler
*/
public static BodyHandler
- * The object acts as a {@link Flow.Subscriber}<{@link ByteBuffer}> to
- * the HTTP client implementation which publishes ByteBuffers containing the
- * response body. The processor converts the incoming buffers of data to
- * some user-defined object type {@code T}.
- *
- * The {@link #getBody()} method returns a {@link CompletionStage}{@code The object acts as a {@link Flow.Subscriber}<{@link List}<{@link
+ * ByteBuffer}>> to the HTTP client implementation, which publishes
+ * unmodifiable lists of ByteBuffers containing the response body. The Flow
+ * of data, as well as the order of ByteBuffers in the Flow lists, is a
+ * strictly ordered representation of the response body. Both the Lists and
+ * the ByteBuffers, once passed to the subscriber, are no longer used by the
+ * HTTP client. The subscriber converts the incoming buffers of data to some
+ * user-defined object type {@code T}.
+ *
+ * The {@link #getBody()} method returns a {@link CompletionStage}{@code
+ *
- * The {@link HttpResponse} using this processor is available after the
- * entire response has been read.
+ *
+ * The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
*
* @param charset the character set to convert the String with
- * @return a body processor
+ * @return a body subscriber
*/
- public static BodyProcessor
- * The {@link HttpResponse} using this processor is available after the
- * entire response has been read.
*
- * @return a body processor
+ * The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
+ *
+ * @return a body subscriber
*/
- public static BodyProcessor
- * The {@link HttpResponse} using this processor is available after the
- * entire response has been read.
+ * with the given options using {@link FileChannel#open(Path,OpenOption...)
+ * FileChannel.open} just before the body is read. Any exception thrown
+ * will be returned or thrown from {@link HttpClient#send(HttpRequest,
+ * BodyHandler) HttpClient::send} or {@link HttpClient#sendAsync(HttpRequest,
+ * BodyHandler) HttpClient::sendAsync} as appropriate.
+ *
+ * The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
*
* @param file the file to store the body in
* @param openOptions the list of options to open the file with
- * @return a body processor
+ * @return a body subscriber
+ * @throws SecurityException If a security manager has been installed
+ * and it denies {@link SecurityManager#checkWrite(String)
+ * write access} to the file. The {@link
+ * SecurityManager#checkDelete(String) checkDelete} method is
+ * invoked to check delete access if the file is opened with the
+ * {@code DELETE_ON_CLOSE} option.
+ */
+ public static BodySubscriber The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
+ *
+ * @param file the file to store the body in
+ * @return a body subscriber
+ * @throws SecurityException if a security manager has been installed
+ * and it denies {@link SecurityManager#checkWrite(String)
+ * write access} to the file
*/
- public static BodyProcessor
- * The {@link HttpResponse} using this processor is available after the
- * entire response has been read.
+ * will contain a non empty {@code Optional}, except for the final
+ * invocation after all body data has been read, when the {@code
+ * Optional} will be empty.
+ *
+ * The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
*
* @param consumer a Consumer of byte arrays
- * @return a BodyProcessor
+ * @return a BodySubscriber
*/
- public static BodyProcessor
- * The {@link HttpResponse} using this processor is available after the
- * entire response has been read.
+ * Returns a {@code BodySubscriber} which streams the response body as
+ * an {@link InputStream}.
*
- * @param file the file to store the body in
- * @return a body processor
+ * The {@link HttpResponse} using this subscriber is available
+ * immediately after the response headers have been read, without
+ * requiring to wait for the entire body to be processed. The response
+ * body can then be read directly from the {@link InputStream}.
+ *
+ * @apiNote To ensure that all resources associated with the
+ * corresponding exchange are properly released the caller must
+ * ensure to either read all bytes until EOF is reached, or call
+ * {@link InputStream#close} if it is unable or unwilling to do so.
+ * Calling {@code close} before exhausting the stream may cause
+ * the underlying HTTP connection to be closed and prevent it
+ * from being reused for subsequent operations.
+ *
+ * @return a body subscriber that streams the response body as an
+ * {@link InputStream}.
*/
- public static BodyProcessor The returned subscriber delegates its {@link #getBody()} method
+ * to the downstream subscriber.
+ *
+ * @param downstream the downstream subscriber
+ * @param bufferSize the buffer size
+ * @return a buffering body subscriber
+ * @throws IllegalArgumentException if {@code bufferSize <= 0}
+ */
+ public static
- * A multi response comprises a main response, and zero or more additional
+ *
+ * A multi response comprises a main response, and zero or more additional
* responses. Each additional response is sent by the server in response to
- * requests that the server also generates. Additional responses are
+ * requests (PUSH_PROMISEs) that the server also generates. Additional responses are
* typically resources that the server expects the client will need which
* are related to the initial request.
*
* Note. Instead of implementing this interface, applications should consider
* first using the mechanism (built on this interface) provided by
- * {@link MultiProcessor#asMap(java.util.function.Function, boolean)
- * MultiProcessor.asMap()} which is a slightly simplified, but
+ * {@link MultiSubscriber#asMap(java.util.function.Function, boolean)
+ * MultiSubscriber.asMap()} which is a slightly simplified, but also
* general purpose interface.
*
* The server generated requests are also known as push promises.
@@ -556,7 +798,7 @@
* the server does not wait for any acknowledgment before sending the
* response, this must be done quickly to avoid unnecessary data transmission.
*
- * {@code MultiProcessor}s are parameterized with a type {@code U} which
+ * {@code MultiSubscriber}s are parameterized with a type {@code U} which
* represents some meaningful aggregate of the responses received. This
* would typically be a collection of response or response body objects.
*
@@ -565,29 +807,43 @@
*
* @since 9
*/
- public interface MultiProcessor {
+ public interface MultiSubscriber {
/**
- * Called for the main request and each push promise that is received.
- * The first call will always be for the main request that was sent
- * by the caller. This {@link HttpRequest} parameter
- * represents the initial request or subsequent PUSH_PROMISE. The
- * implementation must return an {@code Optional} of {@link BodyHandler} for
- * the response body. Different handlers (of the same type) can be returned
- * for different pushes within the same multi send. If no handler
- * (an empty {@code Optional}) is returned, then the push will be canceled. It is
- * an error to not return a valid {@code BodyHandler} for the initial (main) request.
+ * Called for the main request from the user. This {@link HttpRequest}
+ * parameter is the request that was supplied to {@link
+ * HttpClient#sendAsync(HttpRequest, MultiSubscriber)}. The
+ * implementation must return an {@link BodyHandler} for the response
+ * body.
*
- * @param request the main request or subsequent push promise
+ * @param request the request
*
* @return an optional body handler
*/
- Optional Note: The reason for switching to this callback interface rather
* than using CompletableFutures supplied to onRequest() is that there
* is a subtle interaction between those CFs and the CF returned from
* completion() (or when onComplete() was called formerly). The completion()
@@ -615,9 +871,11 @@
* Returns a {@link java.util.concurrent.CompletableFuture}{@code }
* which completes when the aggregate result object itself is available.
* It is expected that the returned {@code CompletableFuture} will depend
- * on one of the given {@code CompletableFuture
- * There are two ways to use these handlers, depending on the value of
- * the completion parameter. If completion is true, then the
+ *
+ * There are two ways to use these handlers, depending on the value
+ * of the completion parameter. If completion is true, then the
* aggregated result will be available after all responses have
* themselves completed. If completion is false, then the
* aggregated result will be available immediately after the last push
* promise was received. In the former case, this implies that all the
* CompletableFutures in the map values will have completed. In the
* latter case, they may or may not have completed yet.
- *
- * The simplest way to use these handlers is to set completion to
+ *
+ * The simplest way to use these handlers is to set completion to
* {@code true}, and then all (results) values in the Map will be
* accessible without blocking.
*
- * See {@link #asMap(java.util.function.Function, boolean)
- * }
+ * See {@link #asMap(java.util.function.Function, boolean)}
* for a code sample of using this interface.
*
+ * See {@link #asMap(Function, boolean)} for a code sample of using
+ * this interface.
+ *
* @param
- * Example usage:
+ *
+ * Example usage:
*
- * The lambda in this example is the simplest possible implementation,
+ *
+ * The lambda in this example is the simplest possible implementation,
* where neither the incoming requests are examined, nor the response
* headers, and every push that the server sends is accepted. When the
* join() call returns, all {@code HttpResponse}s and their associated
* body objects are available.
*
* @param
- *
* {@code
@@ -201,11 +292,11 @@
* }
*
* Note, that even though these pre-defined handlers ignore the status code
- * and headers, this information is still accessible from the {@code HttpResponse}
- * when it is returned.
- *
* {@code
* HttpResponse
*
- * @param > {
/**
- * Returns a {@code CompletionStage} which when completed will return the
- * response body object.
+ * Returns a {@code CompletionStage} which when completed will return
+ * the response body object.
*
* @return a CompletionStage for the response body
*/
public CompletionStage
*
* {@code
@@ -705,26 +966,26 @@
* HttpClient client = HttpClient.newHttpClient();
*
* Map
- *