1/*
2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.incubator.http;
27
28import java.io.IOException;
29import java.io.UncheckedIOException;
30import java.net.URI;
31import jdk.incubator.http.ResponseProcessors.MultiFile;
32import jdk.incubator.http.ResponseProcessors.MultiProcessorImpl;
33import static jdk.incubator.http.internal.common.Utils.unchecked;
34import static jdk.incubator.http.internal.common.Utils.charsetFrom;
35import java.nio.ByteBuffer;
36import java.nio.charset.Charset;
37import java.nio.charset.StandardCharsets;
38import java.nio.file.OpenOption;
39import java.nio.file.Path;
40import java.nio.file.Paths;
41import java.nio.file.StandardOpenOption;
42import java.util.Map;
43import java.util.Optional;
44import java.util.concurrent.CompletableFuture;
45import java.util.concurrent.CompletionStage;
46import java.util.concurrent.Flow;
47import java.util.function.Consumer;
48import java.util.function.Function;
49import javax.net.ssl.SSLParameters;
50
51/**
52 * Represents a response to a {@link HttpRequest}.
53 * {@Incubating}
54 *
55 * <p>A {@code HttpResponse} is available when the response status code and
56 * headers have been received, and typically after the response body has also
57 * been received. This depends on the response body handler provided when
58 * sending the request. In all cases, the response body handler is invoked
59 * before the body is read. This gives applications an opportunity to decide
60 * how to handle the body.
61 *
62 * <p> Methods are provided in this class for accessing the response headers,
63 * and response body.
64 * <p>
65 * <b>Response handlers and processors</b>
66 * <p>
67 * Response bodies are handled at two levels. Application code supplies a response
68 * handler ({@link BodyHandler}) which may examine the response status code
69 * and headers, and which then returns a {@link BodyProcessor} to actually read
70 * (or discard) the body and convert it into some useful Java object type. The handler
71 * can return one of the pre-defined processor types, or a custom processor, or
72 * if the body is to be discarded, it can call {@link BodyProcessor#discard(Object)
73 * BodyProcessor.discard()} and return a processor which discards the response body.
74 * Static implementations of both handlers and processors are provided in
75 * {@link BodyHandler BodyHandler} and {@link BodyProcessor BodyProcessor} respectively.
76 * In all cases, the handler functions provided are convenience implementations
77 * which ignore the supplied status code and
78 * headers and return the relevant pre-defined {@code BodyProcessor}.
79 * <p>
80 * See {@link BodyHandler} for example usage.
81 *
82 * @param <T> the response body type
83 * @since 9
84 */
85public abstract class HttpResponse<T> {
86
87    /**
88     * Creates an HttpResponse.
89     */
90    protected HttpResponse() { }
91
92    /**
93     * Returns the status code for this response.
94     *
95     * @return the response code
96     */
97    public abstract int statusCode();
98
99    /**
100     * Returns the initial {@link HttpRequest} that initiated the exchange.
101     *
102     * @return the request
103     */
104    public abstract HttpRequest request();
105
106    /**
107     * Returns the final {@link HttpRequest} that was sent on the wire for the
108     * exchange ( may, or may not, be the same as the initial request ).
109     *
110     * @return the request
111     */
112    public abstract HttpRequest finalRequest();
113
114    /**
115     * Returns the received response headers.
116     *
117     * @return the response headers
118     */
119    public abstract HttpHeaders headers();
120
121    /**
122     * Returns the received response trailers, if there are any, when they
123     * become available. For many response processor types this will be at the same
124     * time as the {@code HttpResponse} itself is available. In such cases, the
125     * returned {@code CompletableFuture} will be already completed.
126     *
127     * @return a CompletableFuture of the response trailers (may be empty)
128     */
129    public abstract CompletableFuture<HttpHeaders> trailers();
130
131    /**
132     * Returns the body. Depending on the type of {@code T}, the returned body may
133     * represent the body after it was read (such as {@code byte[]}, or
134     * {@code String}, or {@code Path}) or it may represent an object with
135     * which the body is read, such as an {@link java.io.InputStream}.
136     *
137     * @return the body
138     */
139    public abstract T body();
140
141    /**
142     * Returns the {@link javax.net.ssl.SSLParameters} in effect for this
143     * response. Returns {@code null} if this is not a HTTPS response.
144     *
145     * @return the SSLParameters associated with the response
146     */
147    public abstract SSLParameters sslParameters();
148
149    /**
150     * Returns the {@code URI} that the response was received from. This may be
151     * different from the request {@code URI} if redirection occurred.
152     *
153     * @return the URI of the response
154     */
155    public abstract URI uri();
156
157    /**
158     * Returns the HTTP protocol version that was used for this response.
159     *
160     * @return HTTP protocol version
161     */
162    public abstract HttpClient.Version version();
163
164    /**
165     * A handler for response bodies.
166     * {@Incubating}
167     * <p>
168     * This is a function that takes two parameters: the response status code,
169     * and the response headers, and which returns a {@link BodyProcessor}.
170     * The function is always called just before the response body is read. Its
171     * implementation may examine the status code or headers and must decide,
172     * whether to accept the response body or discard it, and if accepting it,
173     * exactly how to handle it.
174     * <p>
175     * Some pre-defined implementations which do not utilize the status code
176     * or headers (meaning the body is always accepted) are defined:
177     * <ul><li>{@link #asByteArray() }</li>
178     * <li>{@link #asByteArrayConsumer(java.util.function.Consumer)
179     * asByteArrayConsumer(Consumer)}</li>
180     * <li>{@link #asFileDownload(java.nio.file.Path,OpenOption...)
181     * asFileDownload(Path,OpenOption...)}</li>
182     * <li>{@link #discard(Object) }</li>
183     * <li>{@link #asString(java.nio.charset.Charset)
184     * asString(Charset)}</li></ul>
185     * <p>
186     * These implementations return the equivalent {@link BodyProcessor}.
187     * Alternatively, the handler can be used to examine the status code
188     * or headers and return different body processors as appropriate.
189     * <p>
190     * <b>Examples of handler usage</b>
191     * <p>
192     * The first example uses one of the predefined handler functions which
193     * ignore the response headers and status, and always process the response
194     * body in the same way.
195     * <pre>
196     * {@code
197     *      HttpResponse<Path> resp = HttpRequest
198     *              .create(URI.create("http://www.foo.com"))
199     *              .GET()
200     *              .response(BodyHandler.asFile(Paths.get("/tmp/f")));
201     * }
202     * </pre>
203     * Note, that even though these pre-defined handlers ignore the status code
204     * and headers, this information is still accessible from the {@code HttpResponse}
205     * when it is returned.
206     * <p>
207     * In the second example, the function returns a different processor depending
208     * on the status code.
209     * <pre>
210     * {@code
211     *      HttpResponse<Path> resp1 = HttpRequest
212     *              .create(URI.create("http://www.foo.com"))
213     *              .GET()
214     *              .response(
215     *                  (status, headers) -> status == 200
216     *                      ? BodyProcessor.asFile(Paths.get("/tmp/f"))
217     *                      : BodyProcessor.discard(Paths.get("/NULL")));
218     * }
219     * </pre>
220     *
221     * @param <T> the response body type.
222     */
223    @FunctionalInterface
224    public interface BodyHandler<T> {
225
226        /**
227         * Returns a {@link BodyProcessor BodyProcessor} considering the given response status
228         * code and headers. This method is always called before the body is read
229         * and its implementation can decide to keep the body and store it somewhere
230         * or else discard it, by  returning the {@code BodyProcessor} returned
231         * from {@link BodyProcessor#discard(java.lang.Object) discard()}.
232         *
233         * @param statusCode the HTTP status code received
234         * @param responseHeaders the response headers received
235         * @return a response body handler
236         */
237        public BodyProcessor<T> apply(int statusCode, HttpHeaders responseHeaders);
238
239        /**
240         * Returns a response body handler which discards the response body and
241         * uses the given value as a replacement for it.
242         *
243         * @param <U> the response body type
244         * @param value the value of U to return as the body
245         * @return a response body handler
246         */
247        public static <U> BodyHandler<U> discard(U value) {
248            return (status, headers) -> BodyProcessor.discard(value);
249        }
250
251        /**
252         * Returns a {@code BodyHandler<String>} that returns a
253         * {@link BodyProcessor BodyProcessor}{@code <String>} obtained from
254         * {@link BodyProcessor#asString(java.nio.charset.Charset)
255         * BodyProcessor.asString(Charset)}. If a charset is provided, the
256         * body is decoded using it. If charset is {@code null} then the processor
257         * tries to determine the character set from the {@code Content-encoding}
258         * header. If that charset is not supported then
259         * {@link java.nio.charset.StandardCharsets#UTF_8 UTF_8} is used.
260         *
261         * @param charset the name of the charset to interpret the body as. If
262         * {@code null} then charset determined from Content-encoding header
263         * @return a response body handler
264         */
265        public static BodyHandler<String> asString(Charset charset) {
266            return (status, headers) -> {
267                if (charset != null) {
268                    return BodyProcessor.asString(charset);
269                }
270                return BodyProcessor.asString(charsetFrom(headers));
271            };
272        }
273
274
275        /**
276         * Returns a {@code BodyHandler<Path>} that returns a
277         * {@link BodyProcessor BodyProcessor}{@code <Path>} obtained from
278         * {@link BodyProcessor#asFile(Path) BodyProcessor.asFile(Path)}.
279         * <p>
280         * When the {@code HttpResponse} object is returned, the body has been completely
281         * written to the file, and {@link #body()} returns a reference to its
282         * {@link Path}.
283         *
284         * @param file the file to store the body in
285         * @return a response body handler
286         */
287        public static BodyHandler<Path> asFile(Path file) {
288            return (status, headers) -> BodyProcessor.asFile(file);
289        }
290
291        /**
292         * Returns a {@code BodyHandler<Path>} that returns a
293         * {@link BodyProcessor BodyProcessor}&lt;{@link Path}&gt;
294         * where the download directory is specified, but the filename is
295         * obtained from the {@code Content-Disposition} response header. The
296         * {@code Content-Disposition} header must specify the <i>attachment</i> type
297         * and must also contain a
298         * <i>filename</i> parameter. If the filename specifies multiple path
299         * components only the final component is used as the filename (with the
300         * given directory name). When the {@code HttpResponse} object is
301         * returned, the body has been completely written to the file and {@link
302         * #body()} returns a {@code Path} object for the file. The returned {@code Path} is the
303         * combination of the supplied directory name and the file name supplied
304         * by the server. If the destination directory does not exist or cannot
305         * be written to, then the response will fail with an {@link IOException}.
306         *
307         * @param directory the directory to store the file in
308         * @param openOptions open options
309         * @return a response body handler
310         */
311        public static BodyHandler<Path> asFileDownload(Path directory, OpenOption... openOptions) {
312            return (status, headers) -> {
313                String dispoHeader = headers.firstValue("Content-Disposition")
314                        .orElseThrow(() -> unchecked(new IOException("No Content-Disposition")));
315                if (!dispoHeader.startsWith("attachment;")) {
316                    throw unchecked(new IOException("Unknown Content-Disposition type"));
317                }
318                int n = dispoHeader.indexOf("filename=");
319                if (n == -1) {
320                    throw unchecked(new IOException("Bad Content-Disposition type"));
321                }
322                int lastsemi = dispoHeader.lastIndexOf(';');
323                String disposition;
324                if (lastsemi < n) {
325                    disposition = dispoHeader.substring(n + 9);
326                } else {
327                    disposition = dispoHeader.substring(n + 9, lastsemi);
328                }
329                Path file = Paths.get(directory.toString(), disposition);
330                return BodyProcessor.asFile(file, openOptions);
331            };
332        }
333
334        /**
335         * Returns a {@code BodyHandler<Path>} that returns a
336         * {@link BodyProcessor BodyProcessor}{@code <Path>} obtained from
337         * {@link BodyProcessor#asFile(java.nio.file.Path, java.nio.file.OpenOption...)
338         * BodyProcessor.asFile(Path,OpenOption...)}.
339         * <p>
340         * When the {@code HttpResponse} object is returned, the body has been completely
341         * written to the file, and {@link #body()} returns a reference to its
342         * {@link Path}.
343         *
344         * @param file the filename to store the body in
345         * @param openOptions any options to use when opening/creating the file
346         * @return a response body handler
347         */
348        public static BodyHandler<Path> asFile(Path file, OpenOption... openOptions) {
349            return (status, headers) -> BodyProcessor.asFile(file, openOptions);
350        }
351
352        /**
353         * Returns a {@code BodyHandler<Void>} that returns a
354         * {@link BodyProcessor BodyProcessor}{@code <Void>} obtained from
355         * {@link BodyProcessor#asByteArrayConsumer(java.util.function.Consumer)
356         * BodyProcessor.asByteArrayConsumer(Consumer)}.
357         * <p>
358         * When the {@code HttpResponse} object is returned, the body has been completely
359         * written to the consumer.
360         *
361         * @param consumer a Consumer to accept the response body
362         * @return a response body handler
363         */
364        public static BodyHandler<Void> asByteArrayConsumer(Consumer<Optional<byte[]>> consumer) {
365            return (status, headers) -> BodyProcessor.asByteArrayConsumer(consumer);
366        }
367
368        /**
369         * Returns a {@code BodyHandler<byte[]>} that returns a
370         * {@link BodyProcessor BodyProcessor}&lt;{@code byte[]}&gt; obtained
371         * from {@link BodyProcessor#asByteArray() BodyProcessor.asByteArray()}.
372         * <p>
373         * When the {@code HttpResponse} object is returned, the body has been completely
374         * written to the byte array.
375         *
376         * @return a response body handler
377         */
378        public static BodyHandler<byte[]> asByteArray() {
379            return (status, headers) -> BodyProcessor.asByteArray();
380        }
381
382        /**
383         * Returns a {@code BodyHandler<String>} that returns a
384         * {@link BodyProcessor BodyProcessor}{@code <String>} obtained from
385         * {@link BodyProcessor#asString(java.nio.charset.Charset)
386         * BodyProcessor.asString(Charset)}. The body is
387         * decoded using the character set specified in
388         * the {@code Content-encoding} response header. If there is no such
389         * header, or the character set is not supported, then
390         * {@link java.nio.charset.StandardCharsets#UTF_8 UTF_8} is used.
391         * <p>
392         * When the {@code HttpResponse} object is returned, the body has been completely
393         * written to the string.
394         *
395         * @return a response body handler
396         */
397        public static BodyHandler<String> asString() {
398            return (status, headers) -> BodyProcessor.asString(charsetFrom(headers));
399        }
400    }
401
402    /**
403     * A processor for response bodies.
404     * {@Incubating}
405     * <p>
406     * The object acts as a {@link Flow.Subscriber}&lt;{@link ByteBuffer}&gt; to
407     * the HTTP client implementation which publishes ByteBuffers containing the
408     * response body. The processor converts the incoming buffers of data to
409     * some user-defined object type {@code T}.
410     * <p>
411     * The {@link #getBody()} method returns a {@link CompletionStage}{@code <T>}
412     * that provides the response body object. The {@code CompletionStage} must
413     * be obtainable at any time. When it completes depends on the nature
414     * of type {@code T}. In many cases, when {@code T} represents the entire body after being
415     * read then it completes after the body has been read. If {@code T} is a streaming
416     * type such as {@link java.io.InputStream} then it completes before the
417     * body has been read, because the calling code uses it to consume the data.
418     *
419     * @param <T> the response body type
420     */
421    public interface BodyProcessor<T>
422            extends Flow.Subscriber<ByteBuffer> {
423
424        /**
425         * Returns a {@code CompletionStage} which when completed will return the
426         * response body object.
427         *
428         * @return a CompletionStage for the response body
429         */
430        public CompletionStage<T> getBody();
431
432        /**
433         * Returns a body processor which stores the response body as a {@code
434         * String} converted using the given {@code Charset}.
435         * <p>
436         * The {@link HttpResponse} using this processor is available after the
437         * entire response has been read.
438         *
439         * @param charset the character set to convert the String with
440         * @return a body processor
441         */
442        public static BodyProcessor<String> asString(Charset charset) {
443            return new ResponseProcessors.ByteArrayProcessor<>(
444                    bytes -> new String(bytes, charset)
445            );
446        }
447
448        /**
449         * Returns a {@code BodyProcessor} which stores the response body as a
450         * byte array.
451         * <p>
452         * The {@link HttpResponse} using this processor is available after the
453         * entire response has been read.
454         *
455         * @return a body processor
456         */
457        public static BodyProcessor<byte[]> asByteArray() {
458            return new ResponseProcessors.ByteArrayProcessor<>(
459                    Function.identity() // no conversion
460            );
461        }
462
463        /**
464         * Returns a {@code BodyProcessor} which stores the response body in a
465         * file opened with the given options and name. The file will be opened
466         * with the given options using
467         * {@link java.nio.channels.FileChannel#open(java.nio.file.Path,java.nio.file.OpenOption...)
468         * FileChannel.open} just before the body is read. Any exception thrown will be returned
469         * or thrown from {@link HttpClient#send(jdk.incubator.http.HttpRequest,
470         * jdk.incubator.http.HttpResponse.BodyHandler) HttpClient::send}
471         * or {@link HttpClient#sendAsync(jdk.incubator.http.HttpRequest,
472         * jdk.incubator.http.HttpResponse.BodyHandler) HttpClient::sendAsync}
473         * as appropriate.
474         * <p>
475         * The {@link HttpResponse} using this processor is available after the
476         * entire response has been read.
477         *
478         * @param file the file to store the body in
479         * @param openOptions the list of options to open the file with
480         * @return a body processor
481         */
482        public static BodyProcessor<Path> asFile(Path file, OpenOption... openOptions) {
483            return new ResponseProcessors.PathProcessor(file, openOptions);
484        }
485
486        /**
487         * Returns a {@code BodyProcessor} which provides the incoming body
488         * data to the provided Consumer of {@code Optional<byte[]>}. Each
489         * call to {@link Consumer#accept(java.lang.Object) Consumer.accept()}
490         * will contain a non empty {@code Optional}, except for the final invocation after
491         * all body data has been read, when the {@code Optional} will be empty.
492         * <p>
493         * The {@link HttpResponse} using this processor is available after the
494         * entire response has been read.
495         *
496         * @param consumer a Consumer of byte arrays
497         * @return a BodyProcessor
498         */
499        public static BodyProcessor<Void> asByteArrayConsumer(Consumer<Optional<byte[]>> consumer) {
500            return new ResponseProcessors.ConsumerProcessor(consumer);
501        }
502
503        /**
504         * Returns a {@code BodyProcessor} which stores the response body in a
505         * file opened with the given name. Has the same effect as calling
506         * {@link #asFile(java.nio.file.Path, java.nio.file.OpenOption...) asFile}
507         * with the standard open options {@code CREATE} and {@code WRITE}
508         * <p>
509         * The {@link HttpResponse} using this processor is available after the
510         * entire response has been read.
511         *
512         * @param file the file to store the body in
513         * @return a body processor
514         */
515        public static BodyProcessor<Path> asFile(Path file) {
516            return new ResponseProcessors.PathProcessor(
517                    file,
518                    StandardOpenOption.CREATE, StandardOpenOption.WRITE);
519        }
520
521        /**
522         * Returns a response processor which discards the response body. The
523         * supplied value is the value that will be returned from
524         * {@link HttpResponse#body()}.
525         *
526         * @param <U> The type of the response body
527         * @param value the value to return from HttpResponse.body()
528         * @return a {@code BodyProcessor}
529         */
530        public static <U> BodyProcessor<U> discard(U value) {
531            return new ResponseProcessors.NullProcessor<>(Optional.ofNullable(value));
532        }
533    }
534
535    /**
536     * A response processor for a HTTP/2 multi response.
537     * {@Incubating}
538     * <p>
539     * A multi response comprises a main response, and zero or more additional
540     * responses. Each additional response is sent by the server in response to
541     * requests that the server also generates. Additional responses are
542     * typically resources that the server expects the client will need which
543     * are related to the initial request.
544     * <p>
545     * Note. Instead of implementing this interface, applications should consider
546     * first using the mechanism (built on this interface) provided by
547     * {@link MultiProcessor#asMap(java.util.function.Function, boolean)
548     * MultiProcessor.asMap()} which is a slightly simplified, but
549     * general purpose interface.
550     * <p>
551     * The server generated requests are also known as <i>push promises</i>.
552     * The server is permitted to send any number of these requests up to the
553     * point where the main response is fully received. Therefore, after
554     * completion of the main response, the final number of additional
555     * responses is known. Additional responses may be canceled, but given that
556     * the server does not wait for any acknowledgment before sending the
557     * response, this must be done quickly to avoid unnecessary data transmission.
558     *
559     * <p> {@code MultiProcessor}s are parameterized with a type {@code U} which
560     * represents some meaningful aggregate of the responses received. This
561     * would typically be a collection of response or response body objects.
562     *
563     * @param <U> a type representing the aggregated results
564     * @param <T> a type representing all of the response bodies
565     *
566     * @since 9
567     */
568    public interface MultiProcessor<U,T> {
569        /**
570         * Called for the main request and each push promise that is received.
571         * The first call will always be for the main request that was sent
572         * by the caller. This {@link HttpRequest} parameter
573         * represents the initial request or subsequent PUSH_PROMISE. The
574         * implementation must return an {@code Optional} of {@link BodyHandler} for
575         * the response body. Different handlers (of the same type) can be returned
576         * for different pushes within the same multi send. If no handler
577         * (an empty {@code Optional}) is returned, then the push will be canceled. It is
578         * an error to not return a valid {@code BodyHandler} for the initial (main) request.
579         *
580         * @param request the main request or subsequent push promise
581         *
582         * @return an optional body handler
583         */
584        Optional<BodyHandler<T>> onRequest(HttpRequest request);
585
586        /**
587         * Called for each response received. For each request either one of
588         * onResponse() or onError() is guaranteed to be called, but not both.
589         *
590         * [Note] The reason for switching to this callback interface rather
591         * than using CompletableFutures supplied to onRequest() is that there
592         * is a subtle interaction between those CFs and the CF returned from
593         * completion() (or when onComplete() was called formerly). The completion()
594         * CF will not complete until after all of the work done by the onResponse()
595         * calls is done. Whereas if you just create CF's dependent on a supplied
596         * CF (to onRequest()) then the implementation has no visibility of the
597         * dependent CFs and can't guarantee to call onComplete() (or complete
598         * the completion() CF) after the dependent CFs complete.
599         *
600         * @param response the response received
601         */
602        void onResponse(HttpResponse<T> response);
603
604        /**
605         * Called if an error occurs receiving a response. For each request
606         * either one of onResponse() or onError() is guaranteed to be called,
607         * but not both.
608         *
609         * @param request the main request or subsequent push promise
610         * @param t the Throwable that caused the error
611         */
612        void onError(HttpRequest request, Throwable t);
613
614        /**
615         * Returns a {@link java.util.concurrent.CompletableFuture}{@code <U>}
616         * which completes when the aggregate result object itself is available.
617         * It is expected that the returned {@code CompletableFuture} will depend
618         * on one of the given {@code CompletableFuture<Void}s which themselves complete
619         * after all individual responses associated with the multi response
620         * have completed, or after all push promises have been received.
621         *
622         * @implNote Implementations might follow the pattern shown below
623         * <pre>
624         * {@code
625         *      CompletableFuture<U> completion(
626         *              CompletableFuture<Void> onComplete,
627         *              CompletableFuture<Void> onFinalPushPromise)
628         *      {
629         *          return onComplete.thenApply((v) -> {
630         *              U u = ... instantiate and populate a U instance
631         *              return u;
632         *          });
633         *      }
634         * }
635         * </pre>
636         *
637         * @param onComplete a CompletableFuture which completes after all
638         * responses have been received relating to this multi request.
639         *
640         * @param onFinalPushPromise CompletableFuture which completes after all
641         * push promises have been received.
642         *
643         * @return the aggregate CF response object
644         */
645        CompletableFuture<U> completion(CompletableFuture<Void> onComplete,
646                CompletableFuture<Void> onFinalPushPromise);
647
648        /**
649         * Returns a general purpose handler for multi responses. The aggregated
650         * result object produced by this handler is a
651         * {@code Map<HttpRequest,CompletableFuture<HttpResponse<V>>>}. Each
652         * request (both the original user generated request and each server
653         * generated push promise) is returned as a key of the map. The value
654         * corresponding to each key is a
655         * {@code CompletableFuture<HttpResponse<V>>}.
656         * <p>
657         * There are two ways to use these handlers, depending on the value of
658         * the <i>completion</I> parameter. If completion is true, then the
659         * aggregated result will be available after all responses have
660         * themselves completed. If <i>completion</i> is false, then the
661         * aggregated result will be available immediately after the last push
662         * promise was received. In the former case, this implies that all the
663         * CompletableFutures in the map values will have completed. In the
664         * latter case, they may or may not have completed yet.
665         * <p>
666         * The simplest way to use these handlers is to set completion to
667         * {@code true}, and then all (results) values in the Map will be
668         * accessible without blocking.
669         * <p>
670         * See {@link #asMap(java.util.function.Function, boolean)
671         * }
672         * for a code sample of using this interface.
673         *
674         * @param <V> the body type used for all responses
675         * @param pushHandler a function invoked for each request or push
676         * promise
677         * @param completion {@code true} if the aggregate CompletableFuture
678         * completes after all responses have been received, or {@code false}
679         * after all push promises received.
680         *
681         * @return a MultiProcessor
682         */
683        public static <V> MultiProcessor<MultiMapResult<V>,V> asMap(
684            Function<HttpRequest, Optional<HttpResponse.BodyHandler<V>>> pushHandler,
685                boolean completion) {
686
687            return new MultiProcessorImpl<V>(pushHandler, completion);
688        }
689
690        /**
691         * Returns a general purpose handler for multi responses. This is a
692         * convenience method which invokes {@link #asMap(java.util.function.Function,boolean)
693         * asMap(Function, true)} meaning that the aggregate result
694         * object completes after all responses have been received.
695         * <p>
696         * <b>Example usage:</b>
697         * <br>
698         * <pre>
699         * {@code
700         *          HttpRequest request = HttpRequest.newBuilder()
701         *                  .uri(URI.create("https://www.foo.com/"))
702         *                  .GET()
703         *                  .build();
704         *
705         *          HttpClient client = HttpClient.newHttpClient();
706         *
707         *          Map<HttpRequest,CompletableFuture<HttpResponse<String>>> results = client
708         *              .sendAsync(request, MultiProcessor.asMap(
709         *                  (req) -> Optional.of(HttpResponse.BodyHandler.asString())))
710         *              .join();
711         * }</pre>
712         * <p>
713         * The lambda in this example is the simplest possible implementation,
714         * where neither the incoming requests are examined, nor the response
715         * headers, and every push that the server sends is accepted. When the
716         * join() call returns, all {@code HttpResponse}s and their associated
717         * body objects are available.
718         *
719         * @param <V> the body type used for all responses
720         * @param pushHandler a function invoked for each request or push
721         * promise
722         * @return a MultiProcessor
723         */
724        public static <V> MultiProcessor<MultiMapResult<V>,V> asMap(
725            Function<HttpRequest, Optional<HttpResponse.BodyHandler<V>>> pushHandler) {
726
727            return asMap(pushHandler, true);
728        }
729
730    }
731}
732