23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package jdk.incubator.http; |
26 package jdk.incubator.http; |
27 |
27 |
|
28 import java.io.BufferedReader; |
28 import java.io.IOException; |
29 import java.io.IOException; |
29 import java.io.InputStream; |
30 import java.io.InputStream; |
30 import java.net.URI; |
31 import java.net.URI; |
31 import jdk.incubator.http.ResponseSubscribers.MultiSubscriberImpl; |
32 import jdk.incubator.http.ResponseSubscribers.MultiSubscriberImpl; |
32 import static jdk.incubator.http.internal.common.Utils.unchecked; |
33 import static jdk.incubator.http.internal.common.Utils.unchecked; |
33 import static jdk.incubator.http.internal.common.Utils.charsetFrom; |
34 import static jdk.incubator.http.internal.common.Utils.charsetFrom; |
34 import java.nio.ByteBuffer; |
35 import java.nio.ByteBuffer; |
35 import java.nio.charset.Charset; |
36 import java.nio.charset.Charset; |
36 import java.nio.channels.FileChannel; |
37 import java.nio.channels.FileChannel; |
|
38 import java.nio.charset.StandardCharsets; |
37 import java.nio.file.OpenOption; |
39 import java.nio.file.OpenOption; |
38 import java.nio.file.Path; |
40 import java.nio.file.Path; |
39 import java.nio.file.Paths; |
41 import java.nio.file.Paths; |
40 import java.nio.file.StandardOpenOption; |
42 import java.nio.file.StandardOpenOption; |
41 import java.security.AccessControlContext; |
43 import java.security.AccessControlContext; |
42 import java.util.Arrays; |
|
43 import java.util.List; |
44 import java.util.List; |
44 import java.util.Objects; |
45 import java.util.Objects; |
45 import java.util.Optional; |
46 import java.util.Optional; |
46 import java.util.concurrent.CompletableFuture; |
47 import java.util.concurrent.CompletableFuture; |
47 import java.util.concurrent.CompletionStage; |
48 import java.util.concurrent.CompletionStage; |
48 import java.util.concurrent.Flow; |
49 import java.util.concurrent.Flow; |
49 import java.util.concurrent.Flow.Subscriber; |
50 import java.util.concurrent.Flow.Subscriber; |
50 import java.util.function.Consumer; |
51 import java.util.function.Consumer; |
51 import java.util.function.Function; |
52 import java.util.function.Function; |
|
53 import java.util.stream.Stream; |
52 import javax.net.ssl.SSLParameters; |
54 import javax.net.ssl.SSLParameters; |
53 |
55 |
54 /** |
56 /** |
55 * Represents a response to a {@link HttpRequest}. |
57 * Represents a response to a {@link HttpRequest}. |
56 * {@Incubating} |
58 * {@Incubating} |
397 return (status, headers) -> BodySubscriber.fromSubscriber(subscriber, |
399 return (status, headers) -> BodySubscriber.fromSubscriber(subscriber, |
398 finisher); |
400 finisher); |
399 } |
401 } |
400 |
402 |
401 /** |
403 /** |
|
404 * Returns a response body handler that returns a {@link BodySubscriber |
|
405 * BodySubscriber}{@code <Void>} obtained from {@link |
|
406 * BodySubscriber#fromLineSubscriber(Subscriber, Function, Charset, String) |
|
407 * BodySubscriber.fromLineSubscriber(subscriber, s -> null, charset, null)}, |
|
408 * with the given {@code subscriber}. |
|
409 * The {@link Charset charset} used to decode the response body bytes is |
|
410 * obtained from the HTTP response headers as specified by {@link #asString()}, |
|
411 * and lines are delimited in the manner of {@link BufferedReader#readLine()}. |
|
412 * |
|
413 * <p> The response body is not available through this, or the {@code |
|
414 * HttpResponse} API, but instead all response body is forwarded to the |
|
415 * given {@code subscriber}, which should make it available, if |
|
416 * appropriate, through some other mechanism, e.g. an entry in a |
|
417 * database, etc. |
|
418 * |
|
419 * @apiNote This method can be used as an adapter between {@code |
|
420 * BodySubscriber} and {@code Flow.Subscriber}. |
|
421 * |
|
422 * <p> For example: |
|
423 * <pre> {@code |
|
424 * TextSubscriber subscriber = new TextSubscriber(); |
|
425 * HttpResponse<Void> response = client.sendAsync(request, |
|
426 * BodyHandler.fromLineSubscriber(subscriber, "\n")).join(); |
|
427 * System.out.println(response.statusCode()); |
|
428 * }</pre> |
|
429 * |
|
430 * @param subscriber the subscriber |
|
431 * @return a response body handler |
|
432 */ |
|
433 public static BodyHandler<Void> |
|
434 fromLineSubscriber(Subscriber<? super String> subscriber) { |
|
435 Objects.requireNonNull(subscriber); |
|
436 return (status, headers) |
|
437 -> BodySubscriber.fromLineSubscriber(subscriber, s -> null, |
|
438 charsetFrom(headers), null); |
|
439 } |
|
440 |
|
441 /** |
|
442 * Returns a response body handler that returns a {@link BodySubscriber |
|
443 * BodySubscriber}{@code <T>} obtained from {@link |
|
444 * BodySubscriber#fromLineSubscriber(Subscriber, Function, Charset, String) |
|
445 * BodySubscriber.fromLineSubscriber(subscriber, finisher, charset, lineSeparator)}, |
|
446 * with the given {@code subscriber}, {@code finisher} function, and line separator. |
|
447 * The {@link Charset charset} used to decode the response body bytes is |
|
448 * obtained from the HTTP response headers as specified by {@link #asString()}. |
|
449 * |
|
450 * <p> The given {@code finisher} function is applied after the given |
|
451 * subscriber's {@code onComplete} has been invoked. The {@code finisher} |
|
452 * function is invoked with the given subscriber, and returns a value |
|
453 * that is set as the response's body. |
|
454 * |
|
455 * @apiNote This method can be used as an adapter between {@code |
|
456 * BodySubscriber} and {@code Flow.Subscriber}. |
|
457 * |
|
458 * <p> For example: |
|
459 * <pre> {@code |
|
460 * TextSubscriber subscriber = ...; // accumulates bytes and transforms them into a String |
|
461 * HttpResponse<String> response = client.sendAsync(request, |
|
462 * BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult, "\n")).join(); |
|
463 * String text = response.body(); |
|
464 * }</pre> |
|
465 * |
|
466 * @param <S> the type of the Subscriber |
|
467 * @param <T> the type of the response body |
|
468 * @param subscriber the subscriber |
|
469 * @param finisher a function to be applied after the subscriber has completed |
|
470 * @param lineSeparator an optional line separator: can be {@code null}, |
|
471 * in which case lines will be delimited in the manner of |
|
472 * {@link BufferedReader#readLine()}. |
|
473 * @return a response body handler |
|
474 * @throws IllegalArgumentException if the supplied {@code lineSeparator} is the empty string. |
|
475 */ |
|
476 public static <S extends Subscriber<? super String>,T> BodyHandler<T> |
|
477 fromLineSubscriber(S subscriber, Function<S,T> finisher, String lineSeparator) { |
|
478 Objects.requireNonNull(subscriber); |
|
479 Objects.requireNonNull(finisher); |
|
480 // implicit null check |
|
481 if (lineSeparator != null && lineSeparator.isEmpty()) |
|
482 throw new IllegalArgumentException("empty line separator"); |
|
483 return (status, headers) -> |
|
484 BodySubscriber.fromLineSubscriber(subscriber, finisher, |
|
485 charsetFrom(headers), lineSeparator); |
|
486 } |
|
487 |
|
488 /** |
402 * Returns a response body handler which discards the response body and |
489 * Returns a response body handler which discards the response body and |
403 * uses the given value as a replacement for it. |
490 * uses the given value as a replacement for it. |
404 * |
491 * |
405 * @param <U> the response body type |
492 * @param <U> the response body type |
406 * @param value the value of U to return as the body, may be {@code null} |
493 * @param value the value of U to return as the body, may be {@code null} |
540 public static BodyHandler<InputStream> asInputStream() { |
627 public static BodyHandler<InputStream> asInputStream() { |
541 return (status, headers) -> BodySubscriber.asInputStream(); |
628 return (status, headers) -> BodySubscriber.asInputStream(); |
542 } |
629 } |
543 |
630 |
544 /** |
631 /** |
|
632 * Returns a {@code BodyHandler<Stream<String>>} that returns a |
|
633 * {@link BodySubscriber BodySubscriber}{@code <Stream<String>>} obtained from |
|
634 * {@link BodySubscriber#asLines(Charset)} |
|
635 * BodySubscriber.asLines(charset)}. |
|
636 * The {@link Charset charset} used to decode the response body bytes is |
|
637 * obtained from the HTTP response headers as specified by {@link #asString()}, |
|
638 * and lines are delimited in the manner of {@link BufferedReader#readLine()}. |
|
639 * |
|
640 * <p> When the {@code HttpResponse} object is returned, the body may |
|
641 * not have been completely received. |
|
642 * |
|
643 * @return a response body handler |
|
644 */ |
|
645 public static BodyHandler<Stream<String>> asLines() { |
|
646 return (status, headers) -> |
|
647 BodySubscriber.asLines(charsetFrom(headers)); |
|
648 } |
|
649 |
|
650 /** |
545 * Returns a {@code BodyHandler<Void>} that returns a |
651 * Returns a {@code BodyHandler<Void>} that returns a |
546 * {@link BodySubscriber BodySubscriber}{@code <Void>} obtained from |
652 * {@link BodySubscriber BodySubscriber}{@code <Void>} obtained from |
547 * {@link BodySubscriber#asByteArrayConsumer(Consumer) |
653 * {@link BodySubscriber#asByteArrayConsumer(Consumer) |
548 * BodySubscriber.asByteArrayConsumer(Consumer)}. |
654 * BodySubscriber.asByteArrayConsumer(Consumer)}. |
549 * |
655 * |
576 * Returns a {@code BodyHandler<String>} that returns a |
682 * Returns a {@code BodyHandler<String>} that returns a |
577 * {@link BodySubscriber BodySubscriber}{@code <String>} obtained from |
683 * {@link BodySubscriber BodySubscriber}{@code <String>} obtained from |
578 * {@link BodySubscriber#asString(java.nio.charset.Charset) |
684 * {@link BodySubscriber#asString(java.nio.charset.Charset) |
579 * BodySubscriber.asString(Charset)}. The body is |
685 * BodySubscriber.asString(Charset)}. The body is |
580 * decoded using the character set specified in |
686 * decoded using the character set specified in |
581 * the {@code Content-encoding} response header. If there is no such |
687 * the {@code Content-type} response header. If there is no such |
582 * header, or the character set is not supported, then |
688 * header, or the character set is not supported, then |
583 * {@link java.nio.charset.StandardCharsets#UTF_8 UTF_8} is used. |
689 * {@link java.nio.charset.StandardCharsets#UTF_8 UTF_8} is used. |
584 * |
690 * |
585 * <p> When the {@code HttpResponse} object is returned, the body has |
691 * <p> When the {@code HttpResponse} object is returned, the body has |
586 * been completely written to the string. |
692 * been completely written to the string. |
707 */ |
813 */ |
708 public static <S extends Subscriber<? super List<ByteBuffer>>,T> BodySubscriber<T> |
814 public static <S extends Subscriber<? super List<ByteBuffer>>,T> BodySubscriber<T> |
709 fromSubscriber(S subscriber, |
815 fromSubscriber(S subscriber, |
710 Function<S,T> finisher) { |
816 Function<S,T> finisher) { |
711 return new ResponseSubscribers.SubscriberAdapter<S,T>(subscriber, finisher); |
817 return new ResponseSubscribers.SubscriberAdapter<S,T>(subscriber, finisher); |
|
818 } |
|
819 |
|
820 /** |
|
821 * Returns a body subscriber that forwards all response body to the |
|
822 * given {@code Flow.Subscriber}, lines by lines. |
|
823 * The {@linkplain #getBody()} completion |
|
824 * stage} of the returned body subscriber completes after one of the |
|
825 * given subscribers {@code onComplete} or {@code onError} has been |
|
826 * invoked. |
|
827 * Bytes are decoded using the {@linkplain StandardCharsets#UTF_8 |
|
828 * UTF-8} charset, and lines are delimited in the manner of |
|
829 * {@link BufferedReader#readLine()}. |
|
830 * |
|
831 * @apiNote This method can be used as an adapter between {@code |
|
832 * BodySubscriber} and {@code Flow.Subscriber}. |
|
833 * |
|
834 * @implNote This is equivalent to calling <pre>{@code |
|
835 * fromLineSubscriber(subscriber, s -> null, StandardCharsets.UTF_8, null) |
|
836 * }</pre> |
|
837 * |
|
838 * @param <S> the type of the Subscriber |
|
839 * @param subscriber the subscriber |
|
840 * @return a body subscriber |
|
841 */ |
|
842 public static <S extends Subscriber<? super String>> BodySubscriber<Void> |
|
843 fromLineSubscriber(S subscriber) { |
|
844 return fromLineSubscriber(subscriber, s -> null, |
|
845 StandardCharsets.UTF_8, null); |
|
846 } |
|
847 |
|
848 /** |
|
849 * Returns a body subscriber that forwards all response body to the |
|
850 * given {@code Flow.Subscriber}, lines by lines. |
|
851 * The {@linkplain #getBody()} completion |
|
852 * stage} of the returned body subscriber completes after one of the |
|
853 * given subscribers {@code onComplete} or {@code onError} has been |
|
854 * invoked. |
|
855 * |
|
856 * <p> The given {@code finisher} function is applied after the given |
|
857 * subscriber's {@code onComplete} has been invoked. The {@code finisher} |
|
858 * function is invoked with the given subscriber, and returns a value |
|
859 * that is set as the response's body. |
|
860 * |
|
861 * @apiNote This method can be used as an adapter between {@code |
|
862 * BodySubscriber} and {@code Flow.Subscriber}. |
|
863 * |
|
864 * @param <S> the type of the Subscriber |
|
865 * @param <T> the type of the response body |
|
866 * @param subscriber the subscriber |
|
867 * @param finisher a function to be applied after the subscriber has |
|
868 * completed |
|
869 * @param charset a {@link Charset} to decode the bytes |
|
870 * @param lineSeparator an optional line separator: can be {@code null}, |
|
871 * in which case lines will be delimited in the manner of |
|
872 * {@link BufferedReader#readLine()}. |
|
873 * @return a body subscriber |
|
874 * @throws IllegalArgumentException if the supplied {@code lineSeparator} is the empty string. |
|
875 */ |
|
876 public static <S extends Subscriber<? super String>,T> BodySubscriber<T> |
|
877 fromLineSubscriber(S subscriber, |
|
878 Function<S,T> finisher, |
|
879 Charset charset, |
|
880 String lineSeparator) { |
|
881 return LineSubscriberAdapter.create(subscriber, |
|
882 finisher, charset, lineSeparator); |
712 } |
883 } |
713 |
884 |
714 /** |
885 /** |
715 * Returns a body subscriber which stores the response body as a {@code |
886 * Returns a body subscriber which stores the response body as a {@code |
716 * String} converted using the given {@code Charset}. |
887 * String} converted using the given {@code Charset}. |
842 * @return a body subscriber that streams the response body as an |
1013 * @return a body subscriber that streams the response body as an |
843 * {@link InputStream}. |
1014 * {@link InputStream}. |
844 */ |
1015 */ |
845 public static BodySubscriber<InputStream> asInputStream() { |
1016 public static BodySubscriber<InputStream> asInputStream() { |
846 return new ResponseSubscribers.HttpResponseInputStream(); |
1017 return new ResponseSubscribers.HttpResponseInputStream(); |
|
1018 } |
|
1019 |
|
1020 /** |
|
1021 * Returns a {@code BodySubscriber} which streams the response body as |
|
1022 * a {@link Stream Stream<String>}, where each string in the stream |
|
1023 * corresponds to a line as defined by {@link BufferedReader#lines()}. |
|
1024 * |
|
1025 * <p> The {@link HttpResponse} using this subscriber is available |
|
1026 * immediately after the response headers have been read, without |
|
1027 * requiring to wait for the entire body to be processed. The response |
|
1028 * body can then be read directly from the {@link Stream}. |
|
1029 * |
|
1030 * @apiNote To ensure that all resources associated with the |
|
1031 * corresponding exchange are properly released the caller must |
|
1032 * ensure to either read all lines until the stream is exhausted, |
|
1033 * or call {@link Stream#close} if it is unable or unwilling to do so. |
|
1034 * Calling {@code close} before exhausting the stream may cause |
|
1035 * the underlying HTTP connection to be closed and prevent it |
|
1036 * from being reused for subsequent operations. |
|
1037 * |
|
1038 * @return a body subscriber that streams the response body as a |
|
1039 * {@link Stream Stream<String>}. |
|
1040 * |
|
1041 * @see BufferedReader#lines() |
|
1042 */ |
|
1043 public static BodySubscriber<Stream<String>> asLines(Charset charset) { |
|
1044 return ResponseSubscribers.HttpLineStream.create(charset); |
847 } |
1045 } |
848 |
1046 |
849 /** |
1047 /** |
850 * Returns a response subscriber which discards the response body. The |
1048 * Returns a response subscriber which discards the response body. The |
851 * supplied value is the value that will be returned from |
1049 * supplied value is the value that will be returned from |