src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java
branchhttp-client-branch
changeset 56008 bbd688c6fbbb
parent 55973 4d9b002587db
parent 48408 4f830b447edf
child 56009 cf8792f51dee
equal deleted inserted replaced
55993:087a6b6d4955 56008:bbd688c6fbbb
    44 import java.util.Objects;
    44 import java.util.Objects;
    45 import java.util.Optional;
    45 import java.util.Optional;
    46 import java.util.concurrent.CompletableFuture;
    46 import java.util.concurrent.CompletableFuture;
    47 import java.util.concurrent.CompletionStage;
    47 import java.util.concurrent.CompletionStage;
    48 import java.util.concurrent.Flow;
    48 import java.util.concurrent.Flow;
       
    49 import java.util.concurrent.Flow.Subscriber;
    49 import java.util.function.Consumer;
    50 import java.util.function.Consumer;
    50 import java.util.function.Function;
    51 import java.util.function.Function;
    51 import javax.net.ssl.SSLParameters;
    52 import javax.net.ssl.SSLParameters;
    52 
    53 
    53 /**
    54 /**
   327          * @return a body subscriber
   328          * @return a body subscriber
   328          */
   329          */
   329         public BodySubscriber<T> apply(int statusCode, HttpHeaders responseHeaders);
   330         public BodySubscriber<T> apply(int statusCode, HttpHeaders responseHeaders);
   330 
   331 
   331         /**
   332         /**
       
   333          * Returns a response body handler that returns a {@link BodySubscriber
       
   334          * BodySubscriber}{@code <Void>} obtained from {@linkplain
       
   335          * BodySubscriber#fromSubscriber(Subscriber)}, with the given
       
   336          * {@code subscriber}.
       
   337          *
       
   338          * <p> The response body is not available through this, or the {@code
       
   339          * HttpResponse} API, but instead all response body is forwarded to the
       
   340          * given {@code subscriber}, which should make it available, if
       
   341          * appropriate, through some other mechanism, e.g. an entry in a
       
   342          * database, etc.
       
   343          *
       
   344          * @apiNote This method can be used as an adapter between {@code
       
   345          * BodySubscriber} and {@code Flow.Subscriber}.
       
   346          *
       
   347          * <p> For example:
       
   348          * <pre> {@code
       
   349          *  TextSubscriber subscriber = new TextSubscriber();
       
   350          *  HttpResponse<Void> response = client.sendAsync(request,
       
   351          *      BodyHandler.fromSubscriber(subscriber)).join();
       
   352          *  System.out.println(response.statusCode());
       
   353          * }</pre>
       
   354          *
       
   355          * @param subscriber the subscriber
       
   356          * @return a response body handler
       
   357          */
       
   358         public static BodyHandler<Void>
       
   359         fromSubscriber(Subscriber<? super List<ByteBuffer>> subscriber) {
       
   360             Objects.requireNonNull(subscriber);
       
   361             return (status, headers) -> BodySubscriber.fromSubscriber(subscriber,
       
   362                                                                       s -> null);
       
   363         }
       
   364 
       
   365         /**
       
   366          * Returns a response body handler that returns a {@link BodySubscriber
       
   367          * BodySubscriber}{@code <T>} obtained from {@link
       
   368          * BodySubscriber#fromSubscriber(Subscriber, Function)}, with the
       
   369          * given {@code subscriber} and {@code finisher} function.
       
   370          *
       
   371          * <p> The given {@code finisher} function is applied after the given
       
   372          * subscriber's {@code onComplete} has been invoked. The {@code finisher}
       
   373          * function is invoked with the given subscriber, and returns a value
       
   374          * that is set as the response's body.
       
   375          *
       
   376          * @apiNote This method can be used as an adapter between {@code
       
   377          * BodySubscriber} and {@code Flow.Subscriber}.
       
   378          *
       
   379          * <p> For example:
       
   380          * <pre> {@code
       
   381          * TextSubscriber subscriber = ...;  // accumulates bytes and transforms them into a String
       
   382          * HttpResponse<String> response = client.sendAsync(request,
       
   383          *     BodyHandler.fromSubscriber(subscriber, TextSubscriber::getTextResult)).join();
       
   384          * String text = response.body();
       
   385          * }</pre>
       
   386          *
       
   387          * @param <S> the type of the Subscriber
       
   388          * @param <T> the type of the response body
       
   389          * @param subscriber the subscriber
       
   390          * @param finisher a function to be applied after the subscriber has completed
       
   391          * @return a response body handler
       
   392          */
       
   393         public static <S extends Subscriber<? super List<ByteBuffer>>,T> BodyHandler<T>
       
   394         fromSubscriber(S subscriber, Function<S,T> finisher) {
       
   395             Objects.requireNonNull(subscriber);
       
   396             Objects.requireNonNull(finisher);
       
   397             return (status, headers) -> BodySubscriber.fromSubscriber(subscriber,
       
   398                                                                       finisher);
       
   399         }
       
   400 
       
   401         /**
   332          * Returns a response body handler which discards the response body and
   402          * Returns a response body handler which discards the response body and
   333          * uses the given value as a replacement for it.
   403          * uses the given value as a replacement for it.
   334          *
   404          *
   335          * @param <U> the response body type
   405          * @param <U> the response body type
   336          * @param value the value of U to return as the body, may be {@code null}
   406          * @param value the value of U to return as the body, may be {@code null}
   342 
   412 
   343         /**
   413         /**
   344          * Returns a {@code BodyHandler<String>} that returns a
   414          * Returns a {@code BodyHandler<String>} that returns a
   345          * {@link BodySubscriber BodySubscriber}{@code <String>} obtained from
   415          * {@link BodySubscriber BodySubscriber}{@code <String>} obtained from
   346          * {@link BodySubscriber#asString(Charset) BodySubscriber.asString(Charset)}.
   416          * {@link BodySubscriber#asString(Charset) BodySubscriber.asString(Charset)}.
   347          * If a charset is provided, the body is decoded using it. If charset is
   417          * The body is decoded using the given character set.
   348          * {@code null} then the handler tries to determine the character set
   418          *
   349          * from the {@code Content-encoding} header. If that charset is not
   419          * @param charset the character set to convert the body with
   350          * supported then {@link java.nio.charset.StandardCharsets#UTF_8 UTF_8}
       
   351          * is used.
       
   352          *
       
   353          * @param charset The name of the charset to interpret the body as. If
       
   354          *                {@code null} then the charset is determined from the
       
   355          *                <i>Content-encoding</i> header.
       
   356          * @return a response body handler
   420          * @return a response body handler
   357          */
   421          */
   358         public static BodyHandler<String> asString(Charset charset) {
   422         public static BodyHandler<String> asString(Charset charset) {
   359             return (status, headers) -> {
   423             Objects.requireNonNull(charset);
   360                 if (charset != null) {
   424             return (status, headers) -> BodySubscriber.asString(charset);
   361                     return BodySubscriber.asString(charset);
       
   362                 }
       
   363                 return BodySubscriber.asString(charsetFrom(headers));
       
   364             };
       
   365         }
   425         }
   366 
   426 
   367         /**
   427         /**
   368          * Returns a {@code BodyHandler<Path>} that returns a
   428          * Returns a {@code BodyHandler<Path>} that returns a
   369          * {@link BodySubscriber BodySubscriber}{@code <Path>} obtained from
   429          * {@link BodySubscriber BodySubscriber}{@code <Path>} obtained from
   384          *          invoked to check delete access if the file is opened with
   444          *          invoked to check delete access if the file is opened with
   385          *          the {@code DELETE_ON_CLOSE} option.
   445          *          the {@code DELETE_ON_CLOSE} option.
   386          */
   446          */
   387         public static BodyHandler<Path> asFile(Path file, OpenOption... openOptions) {
   447         public static BodyHandler<Path> asFile(Path file, OpenOption... openOptions) {
   388             Objects.requireNonNull(file);
   448             Objects.requireNonNull(file);
       
   449             List<OpenOption> opts = List.of(openOptions);
   389             SecurityManager sm = System.getSecurityManager();
   450             SecurityManager sm = System.getSecurityManager();
   390             if (sm != null) {
   451             if (sm != null) {
   391                 String fn = pathForSecurityCheck(file);
   452                 String fn = pathForSecurityCheck(file);
   392                 sm.checkWrite(fn);
   453                 sm.checkWrite(fn);
   393                 List<OpenOption> opts = Arrays.asList(openOptions);
       
   394                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
   454                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
   395                     sm.checkDelete(fn);
   455                     sm.checkDelete(fn);
   396                 if (opts.contains(StandardOpenOption.READ))
   456                 if (opts.contains(StandardOpenOption.READ))
   397                     sm.checkRead(fn);
   457                     sm.checkRead(fn);
   398             }
   458             }
   448          */
   508          */
   449          //####: check if the dir exists and is writable??
   509          //####: check if the dir exists and is writable??
   450         public static BodyHandler<Path> asFileDownload(Path directory,
   510         public static BodyHandler<Path> asFileDownload(Path directory,
   451                                                        OpenOption... openOptions) {
   511                                                        OpenOption... openOptions) {
   452             Objects.requireNonNull(directory);
   512             Objects.requireNonNull(directory);
       
   513             List<OpenOption> opts = List.of(openOptions);
   453             SecurityManager sm = System.getSecurityManager();
   514             SecurityManager sm = System.getSecurityManager();
   454             if (sm != null) {
   515             if (sm != null) {
   455                 String fn = pathForSecurityCheck(directory);
   516                 String fn = pathForSecurityCheck(directory);
   456                 sm.checkWrite(fn);
   517                 sm.checkWrite(fn);
   457                 List<OpenOption> opts = Arrays.asList(openOptions);
       
   458                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
   518                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
   459                     sm.checkDelete(fn);
   519                     sm.checkDelete(fn);
   460                 if (opts.contains(StandardOpenOption.READ))
   520                 if (opts.contains(StandardOpenOption.READ))
   461                     sm.checkRead(fn);
   521                     sm.checkRead(fn);
   462             }
   522             }
   492          *
   552          *
   493          * @param consumer a Consumer to accept the response body
   553          * @param consumer a Consumer to accept the response body
   494          * @return a response body handler
   554          * @return a response body handler
   495          */
   555          */
   496         public static BodyHandler<Void> asByteArrayConsumer(Consumer<Optional<byte[]>> consumer) {
   556         public static BodyHandler<Void> asByteArrayConsumer(Consumer<Optional<byte[]>> consumer) {
       
   557             Objects.requireNonNull(consumer);
   497             return (status, headers) -> BodySubscriber.asByteArrayConsumer(consumer);
   558             return (status, headers) -> BodySubscriber.asByteArrayConsumer(consumer);
   498         }
   559         }
   499 
   560 
   500         /**
   561         /**
   501          * Returns a {@code BodyHandler<byte[]>} that returns a
   562          * Returns a {@code BodyHandler<byte[]>} that returns a
   545          * @return a body handler
   606          * @return a body handler
   546          * @throws IllegalArgumentException if {@code bufferSize <= 0}
   607          * @throws IllegalArgumentException if {@code bufferSize <= 0}
   547          */
   608          */
   548          public static <T> BodyHandler<T> buffering(BodyHandler<T> downstreamHandler,
   609          public static <T> BodyHandler<T> buffering(BodyHandler<T> downstreamHandler,
   549                                                     int bufferSize) {
   610                                                     int bufferSize) {
       
   611              Objects.requireNonNull(downstreamHandler);
   550              if (bufferSize <= 0)
   612              if (bufferSize <= 0)
   551                  throw new IllegalArgumentException("must be greater than 0");
   613                  throw new IllegalArgumentException("must be greater than 0");
   552              return (status, headers) -> BodySubscriber
   614              return (status, headers) -> BodySubscriber
   553                      .buffering(downstreamHandler.apply(status, headers),
   615                      .buffering(downstreamHandler.apply(status, headers),
   554                                 bufferSize);
   616                                 bufferSize);
   601          * @return a CompletionStage for the response body
   663          * @return a CompletionStage for the response body
   602          */
   664          */
   603         public CompletionStage<T> getBody();
   665         public CompletionStage<T> getBody();
   604 
   666 
   605         /**
   667         /**
       
   668          * Returns a body subscriber that forwards all response body to the
       
   669          * given {@code Flow.Subscriber}. The {@linkplain #getBody()} completion
       
   670          * stage} of the returned body subscriber completes after one of the
       
   671          * given subscribers {@code onComplete} or {@code onError} has been
       
   672          * invoked.
       
   673          *
       
   674          * @apiNote This method can be used as an adapter between {@code
       
   675          * BodySubscriber} and {@code Flow.Subscriber}.
       
   676          *
       
   677          * @param <S> the type of the Subscriber
       
   678          * @param subscriber the subscriber
       
   679          * @return a body subscriber
       
   680          */
       
   681         public static <S extends Subscriber<? super List<ByteBuffer>>> BodySubscriber<Void>
       
   682         fromSubscriber(S subscriber) {
       
   683             return new ResponseSubscribers.SubscriberAdapter<S,Void>(subscriber, s -> null);
       
   684         }
       
   685 
       
   686         /**
       
   687          * Returns a body subscriber that forwards all response body to the
       
   688          * given {@code Flow.Subscriber}. The {@linkplain #getBody()} completion
       
   689          * stage} of the returned body subscriber completes after one of the
       
   690          * given subscribers {@code onComplete} or {@code onError} has been
       
   691          * invoked.
       
   692          *
       
   693          * <p> The given {@code finisher} function is applied after the given
       
   694          * subscriber's {@code onComplete} has been invoked. The {@code finisher}
       
   695          * function is invoked with the given subscriber, and returns a value
       
   696          * that is set as the response's body.
       
   697          *
       
   698          * @apiNote This method can be used as an adapter between {@code
       
   699          * BodySubscriber} and {@code Flow.Subscriber}.
       
   700          *
       
   701          * @param <S> the type of the Subscriber
       
   702          * @param <T> the type of the response body
       
   703          * @param subscriber the subscriber
       
   704          * @param finisher a function to be applied after the subscriber has
       
   705          *                 completed
       
   706          * @return a body subscriber
       
   707          */
       
   708         public static <S extends Subscriber<? super List<ByteBuffer>>,T> BodySubscriber<T>
       
   709         fromSubscriber(S subscriber,
       
   710                        Function<S,T> finisher) {
       
   711             return new ResponseSubscribers.SubscriberAdapter<S,T>(subscriber, finisher);
       
   712         }
       
   713 
       
   714         /**
   606          * Returns a body subscriber which stores the response body as a {@code
   715          * Returns a body subscriber which stores the response body as a {@code
   607          * String} converted using the given {@code Charset}.
   716          * String} converted using the given {@code Charset}.
   608          *
   717          *
   609          * <p> The {@link HttpResponse} using this subscriber is available after
   718          * <p> The {@link HttpResponse} using this subscriber is available after
   610          * the entire response has been read.
   719          * the entire response has been read.
   611          *
   720          *
   612          * @param charset the character set to convert the String with
   721          * @param charset the character set to convert the String with
   613          * @return a body subscriber
   722          * @return a body subscriber
   614          */
   723          */
   615         public static BodySubscriber<String> asString(Charset charset) {
   724         public static BodySubscriber<String> asString(Charset charset) {
       
   725             Objects.requireNonNull(charset);
   616             return new ResponseSubscribers.ByteArraySubscriber<>(
   726             return new ResponseSubscribers.ByteArraySubscriber<>(
   617                     bytes -> new String(bytes, charset)
   727                     bytes -> new String(bytes, charset)
   618             );
   728             );
   619         }
   729         }
   620 
   730 
   660          *          invoked to check delete access if the file is opened with the
   770          *          invoked to check delete access if the file is opened with the
   661          *          {@code DELETE_ON_CLOSE} option.
   771          *          {@code DELETE_ON_CLOSE} option.
   662          */
   772          */
   663         public static BodySubscriber<Path> asFile(Path file, OpenOption... openOptions) {
   773         public static BodySubscriber<Path> asFile(Path file, OpenOption... openOptions) {
   664             Objects.requireNonNull(file);
   774             Objects.requireNonNull(file);
       
   775             List<OpenOption> opts = List.of(openOptions);
   665             SecurityManager sm = System.getSecurityManager();
   776             SecurityManager sm = System.getSecurityManager();
   666             if (sm != null) {
   777             if (sm != null) {
   667                 String fn = pathForSecurityCheck(file);
   778                 String fn = pathForSecurityCheck(file);
   668                 sm.checkWrite(fn);
   779                 sm.checkWrite(fn);
   669                 List<OpenOption> opts = Arrays.asList(openOptions);
       
   670                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
   780                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
   671                     sm.checkDelete(fn);
   781                     sm.checkDelete(fn);
   672                 if (opts.contains(StandardOpenOption.READ))
   782                 if (opts.contains(StandardOpenOption.READ))
   673                     sm.checkRead(fn);
   783                     sm.checkRead(fn);
   674             }
   784             }