src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java
branchhttp-client-branch
changeset 56079 d23b02f37fce
parent 56078 6c11b48a0695
child 56082 1da51fab3032
equal deleted inserted replaced
56078:6c11b48a0695 56079:d23b02f37fce
    33 import java.nio.charset.Charset;
    33 import java.nio.charset.Charset;
    34 import java.nio.channels.FileChannel;
    34 import java.nio.channels.FileChannel;
    35 import java.nio.charset.StandardCharsets;
    35 import java.nio.charset.StandardCharsets;
    36 import java.nio.file.OpenOption;
    36 import java.nio.file.OpenOption;
    37 import java.nio.file.Path;
    37 import java.nio.file.Path;
    38 import java.nio.file.Paths;
       
    39 import java.nio.file.StandardOpenOption;
    38 import java.nio.file.StandardOpenOption;
    40 import java.security.AccessControlContext;
       
    41 import java.util.List;
    39 import java.util.List;
    42 import java.util.Objects;
    40 import java.util.Objects;
    43 import java.util.Optional;
    41 import java.util.Optional;
    44 import java.util.concurrent.CompletableFuture;
    42 import java.util.concurrent.CompletableFuture;
    45 import java.util.concurrent.CompletionStage;
    43 import java.util.concurrent.CompletionStage;
    46 import java.util.concurrent.ConcurrentMap;
    44 import java.util.concurrent.ConcurrentMap;
    47 import java.util.concurrent.Flow;
    45 import java.util.concurrent.Flow;
    48 import java.util.concurrent.Flow.Subscriber;
    46 import java.util.concurrent.Flow.Subscriber;
    49 import java.util.function.BiFunction;
       
    50 import java.util.function.Consumer;
    47 import java.util.function.Consumer;
    51 import java.util.function.Function;
    48 import java.util.function.Function;
    52 import java.util.stream.Stream;
    49 import java.util.stream.Stream;
    53 import javax.net.ssl.SSLParameters;
    50 import javax.net.ssl.SSLParameters;
    54 import jdk.incubator.http.internal.BufferingSubscriber;
    51 import jdk.incubator.http.internal.BufferingSubscriber;
    55 import jdk.incubator.http.internal.LineSubscriberAdapter;
    52 import jdk.incubator.http.internal.LineSubscriberAdapter;
       
    53 import jdk.incubator.http.internal.ResponseBodyHandlers.FileDownloadBodyHandler;
       
    54 import jdk.incubator.http.internal.ResponseBodyHandlers.PathBodyHandler;
       
    55 import jdk.incubator.http.internal.ResponseBodyHandlers.PushPromisesHandlerWithMap;
    56 import jdk.incubator.http.internal.ResponseSubscribers;
    56 import jdk.incubator.http.internal.ResponseSubscribers;
    57 import static jdk.incubator.http.internal.common.Utils.unchecked;
       
    58 import static jdk.incubator.http.internal.common.Utils.charsetFrom;
    57 import static jdk.incubator.http.internal.common.Utils.charsetFrom;
    59 
    58 
    60 /**
    59 /**
    61  * Represents a response to a {@link HttpRequest}.
    60  * Represents a response to a {@link HttpRequest}.
    62  * {@Incubating}
    61  * {@Incubating}
   174 
   173 
   175     private static String pathForSecurityCheck(Path path) {
   174     private static String pathForSecurityCheck(Path path) {
   176         return path.toFile().getPath();
   175         return path.toFile().getPath();
   177     }
   176     }
   178 
   177 
   179     /** A body handler that is further restricted by a given ACC. */
       
   180     interface UntrustedBodyHandler<T> extends BodyHandler<T> {
       
   181         void setAccessControlContext(AccessControlContext acc);
       
   182     }
       
   183 
       
   184     /**
       
   185      * A Path body handler.
       
   186      *
       
   187      * Note: Exists mainly too allow setting of the senders ACC post creation of
       
   188      * the handler.
       
   189      */
       
   190     static class PathBodyHandler implements UntrustedBodyHandler<Path> {
       
   191         private final Path file;
       
   192         private final OpenOption[]openOptions;
       
   193         private volatile AccessControlContext acc;
       
   194 
       
   195         PathBodyHandler(Path file, OpenOption... openOptions) {
       
   196             this.file = file;
       
   197             this.openOptions = openOptions;
       
   198         }
       
   199 
       
   200         @Override
       
   201         public void setAccessControlContext(AccessControlContext acc) {
       
   202             this.acc = acc;
       
   203         }
       
   204 
       
   205         @Override
       
   206         public BodySubscriber<Path> apply(int statusCode, HttpHeaders headers) {
       
   207             ResponseSubscribers.PathSubscriber bs = (ResponseSubscribers.PathSubscriber)
       
   208                     BodySubscriber.asFileImpl(file, openOptions);
       
   209             bs.setAccessControlContext(acc);
       
   210             return bs;
       
   211         }
       
   212     }
       
   213 
       
   214     /* package-private with push promise Map implementation */
       
   215     static class PushPromisesHandlerWithMap<T> implements PushPromiseHandler<T> {
       
   216 
       
   217         private final ConcurrentMap<HttpRequest,CompletableFuture<HttpResponse<T>>> pushPromisesMap;
       
   218         private final Function<HttpRequest,BodyHandler<T>> pushPromiseHandler;
       
   219 
       
   220         PushPromisesHandlerWithMap(Function<HttpRequest,BodyHandler<T>> pushPromiseHandler,
       
   221                                    ConcurrentMap<HttpRequest,CompletableFuture<HttpResponse<T>>> pushPromisesMap) {
       
   222             this.pushPromiseHandler = pushPromiseHandler;
       
   223             this.pushPromisesMap = pushPromisesMap;
       
   224         }
       
   225 
       
   226         @Override
       
   227         public void applyPushPromise(
       
   228             HttpRequest initiatingRequest, HttpRequest pushRequest,
       
   229             Function<BodyHandler<T>,CompletableFuture<HttpResponse<T>>> acceptor)
       
   230         {
       
   231             URI initiatingURI = initiatingRequest.uri();
       
   232             URI pushRequestURI = pushRequest.uri();
       
   233             if (!initiatingURI.getHost().equalsIgnoreCase(pushRequestURI.getHost()))
       
   234                 return;
       
   235 
       
   236             int initiatingPort = initiatingURI.getPort();
       
   237             if (initiatingPort == -1 ) {
       
   238                 if ("https".equalsIgnoreCase(initiatingURI.getScheme()))
       
   239                     initiatingPort = 443;
       
   240                 else
       
   241                     initiatingPort = 80;
       
   242             }
       
   243             int pushPort = pushRequestURI.getPort();
       
   244             if (pushPort == -1 ) {
       
   245                 if ("https".equalsIgnoreCase(pushRequestURI.getScheme()))
       
   246                     pushPort = 443;
       
   247                 else
       
   248                     pushPort = 80;
       
   249             }
       
   250             if (initiatingPort != pushPort)
       
   251                 return;
       
   252 
       
   253             CompletableFuture<HttpResponse<T>> cf =
       
   254                     acceptor.apply(pushPromiseHandler.apply(pushRequest));
       
   255             pushPromisesMap.put(pushRequest, cf);
       
   256         }
       
   257     }
       
   258 
       
   259     // Similar to Path body handler, but for file download. Supports setting ACC.
       
   260     static class FileDownloadBodyHandler implements UntrustedBodyHandler<Path> {
       
   261         private final Path directory;
       
   262         private final OpenOption[]openOptions;
       
   263         private volatile AccessControlContext acc;
       
   264 
       
   265         FileDownloadBodyHandler(Path directory, OpenOption... openOptions) {
       
   266             this.directory = directory;
       
   267             this.openOptions = openOptions;
       
   268         }
       
   269 
       
   270         @Override
       
   271         public void setAccessControlContext(AccessControlContext acc) {
       
   272             this.acc = acc;
       
   273         }
       
   274 
       
   275         @Override
       
   276         public BodySubscriber<Path> apply(int statusCode, HttpHeaders headers) {
       
   277             String dispoHeader = headers.firstValue("Content-Disposition")
       
   278                     .orElseThrow(() -> unchecked(new IOException("No Content-Disposition")));
       
   279             if (!dispoHeader.startsWith("attachment;")) {
       
   280                 throw unchecked(new IOException("Unknown Content-Disposition type"));
       
   281             }
       
   282             int n = dispoHeader.indexOf("filename=");
       
   283             if (n == -1) {
       
   284                 throw unchecked(new IOException("Bad Content-Disposition type"));
       
   285             }
       
   286             int lastsemi = dispoHeader.lastIndexOf(';');
       
   287             String disposition;
       
   288             if (lastsemi < n) {
       
   289                 disposition = dispoHeader.substring(n + 9);
       
   290             } else {
       
   291                 disposition = dispoHeader.substring(n + 9, lastsemi);
       
   292             }
       
   293             Path file = Paths.get(directory.toString(), disposition);
       
   294 
       
   295             ResponseSubscribers.PathSubscriber bs = (ResponseSubscribers.PathSubscriber)
       
   296                     BodySubscriber.asFileImpl(file, openOptions);
       
   297             bs.setAccessControlContext(acc);
       
   298             return bs;
       
   299         }
       
   300     }
       
   301 
   178 
   302     /**
   179     /**
   303      * A handler for response bodies.
   180      * A handler for response bodies.
   304      * {@Incubating}
   181      * {@Incubating}
   305      *
   182      *