src/java.net.http/share/classes/java/net/http/HttpResponse.java
branchhttp-client-branch
changeset 56138 4f92b988600e
parent 56131 99f144742013
child 56139 b3d6203051df
equal deleted inserted replaced
56137:dd867826d55b 56138:4f92b988600e
    31 import java.net.URI;
    31 import java.net.URI;
    32 import java.nio.ByteBuffer;
    32 import java.nio.ByteBuffer;
    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.Files;
    36 import java.nio.file.OpenOption;
    37 import java.nio.file.OpenOption;
    37 import java.nio.file.Path;
    38 import java.nio.file.Path;
    38 import java.nio.file.StandardOpenOption;
       
    39 import java.util.List;
    39 import java.util.List;
    40 import java.util.Objects;
    40 import java.util.Objects;
    41 import java.util.Optional;
    41 import java.util.Optional;
    42 import java.util.concurrent.CompletableFuture;
    42 import java.util.concurrent.CompletableFuture;
    43 import java.util.concurrent.CompletionStage;
    43 import java.util.concurrent.CompletionStage;
    52 import jdk.internal.net.http.LineSubscriberAdapter;
    52 import jdk.internal.net.http.LineSubscriberAdapter;
    53 import jdk.internal.net.http.ResponseBodyHandlers.FileDownloadBodyHandler;
    53 import jdk.internal.net.http.ResponseBodyHandlers.FileDownloadBodyHandler;
    54 import jdk.internal.net.http.ResponseBodyHandlers.PathBodyHandler;
    54 import jdk.internal.net.http.ResponseBodyHandlers.PathBodyHandler;
    55 import jdk.internal.net.http.ResponseBodyHandlers.PushPromisesHandlerWithMap;
    55 import jdk.internal.net.http.ResponseBodyHandlers.PushPromisesHandlerWithMap;
    56 import jdk.internal.net.http.ResponseSubscribers;
    56 import jdk.internal.net.http.ResponseSubscribers;
       
    57 import jdk.internal.net.http.ResponseSubscribers.PathSubscriber;
       
    58 import static java.nio.file.StandardOpenOption.*;
    57 import static jdk.internal.net.http.common.Utils.charsetFrom;
    59 import static jdk.internal.net.http.common.Utils.charsetFrom;
    58 
    60 
    59 /**
    61 /**
    60  * An HTTP response.
    62  * An HTTP response.
    61  *
    63  *
   447          *
   449          *
   448          * <p> When the {@code HttpResponse} object is returned, the body has
   450          * <p> When the {@code HttpResponse} object is returned, the body has
   449          * been completely written to the file, and {@link #body()} returns a
   451          * been completely written to the file, and {@link #body()} returns a
   450          * reference to its {@link Path}.
   452          * reference to its {@link Path}.
   451          *
   453          *
   452          * @param file the filename to store the body in
   454          * <p> Security manager permission checks are performed in this factory
       
   455          * method, when a {@code BodyHandler} is created. Care must be taken
       
   456          * that the {@code BodyHandler} is not shared with untrusted code.
       
   457          *
       
   458          * @param file the file to store the body in
   453          * @param openOptions any options to use when opening/creating the file
   459          * @param openOptions any options to use when opening/creating the file
   454          * @return a response body handler
   460          * @return a response body handler
       
   461          * @throws IllegalArgumentException if an invalid set of open options
       
   462          *          are specified
   455          * @throws SecurityException If a security manager has been installed
   463          * @throws SecurityException If a security manager has been installed
   456          *          and it denies {@link SecurityManager#checkWrite(String)
   464          *          and it denies {@link SecurityManager#checkWrite(String)
   457          *          write access} to the file. The {@link
   465          *          write access} to the file.
   458          *          SecurityManager#checkDelete(String) checkDelete} method is
       
   459          *          invoked to check delete access if the file is opened with
       
   460          *          the {@code DELETE_ON_CLOSE} option.
       
   461          */
   466          */
   462         public static BodyHandler<Path> asFile(Path file, OpenOption... openOptions) {
   467         public static BodyHandler<Path> asFile(Path file, OpenOption... openOptions) {
   463             Objects.requireNonNull(file);
   468             Objects.requireNonNull(file);
   464             List<OpenOption> opts = List.of(openOptions);
   469             List<OpenOption> opts = List.of(openOptions);
       
   470             if (opts.contains(DELETE_ON_CLOSE) || opts.contains(READ)) {
       
   471                 // these options make no sense, since the FileChannel is not exposed
       
   472                 throw new IllegalArgumentException("invalid openOptions: " + opts);
       
   473             }
       
   474 
   465             SecurityManager sm = System.getSecurityManager();
   475             SecurityManager sm = System.getSecurityManager();
   466             if (sm != null) {
   476             if (sm != null) {
   467                 String fn = pathForSecurityCheck(file);
   477                 String fn = pathForSecurityCheck(file);
   468                 sm.checkWrite(fn);
   478                 sm.checkWrite(fn);
   469                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
       
   470                     sm.checkDelete(fn);
       
   471                 if (opts.contains(StandardOpenOption.READ))
       
   472                     sm.checkRead(fn);
       
   473             }
   479             }
   474             return new PathBodyHandler(file, openOptions);
   480             return new PathBodyHandler(file, opts);
   475         }
   481         }
   476 
   482 
   477         /**
   483         /**
   478          * Returns a {@code BodyHandler<Path>} that returns a
   484          * Returns a {@code BodyHandler<Path>} that returns a
   479          * {@link BodySubscriber BodySubscriber}{@code <Path>} obtained from
   485          * {@link BodySubscriber BodySubscriber}{@code <Path>}.
   480          * {@link BodySubscriber#asFile(Path) BodySubscriber.asFile(Path)}.
   486          *
   481          *
   487          * <p> Equivalent to: {@code asFile(file, CREATE, WRITE)}
   482          * <p> When the {@code HttpResponse} object is returned, the body has
   488          *
   483          * been completely written to the file, and {@link #body()} returns a
   489          * <p> Security manager permission checks are performed in this factory
   484          * reference to its {@link Path}.
   490          * method, when a {@code BodyHandler} is created. Care must be taken
       
   491          * that the {@code BodyHandler} is not shared with untrusted code.
   485          *
   492          *
   486          * @param file the file to store the body in
   493          * @param file the file to store the body in
   487          * @return a response body handler
   494          * @return a response body handler
   488          * @throws SecurityException if a security manager has been installed
   495          * @throws SecurityException If a security manager has been installed
   489          *          and it denies {@link SecurityManager#checkWrite(String)
   496          *          and it denies {@link SecurityManager#checkWrite(String)
   490          *          write access} to the file
   497          *          write access} to the file.
   491          */
   498          */
   492         public static BodyHandler<Path> asFile(Path file) {
   499         public static BodyHandler<Path> asFile(Path file) {
   493             return BodyHandler.asFile(file, StandardOpenOption.CREATE,
   500             return BodyHandler.asFile(file, CREATE, WRITE);
   494                                             StandardOpenOption.WRITE);
       
   495         }
   501         }
   496 
   502 
   497         /**
   503         /**
   498          * Returns a {@code BodyHandler<Path>} that returns a
   504          * Returns a {@code BodyHandler<Path>} that returns a
   499          * {@link BodySubscriber BodySubscriber}&lt;{@link Path}&gt;
   505          * {@link BodySubscriber BodySubscriber}&lt;{@link Path}&gt;
   509          * {@code Path} object for the file. The returned {@code Path} is the
   515          * {@code Path} object for the file. The returned {@code Path} is the
   510          * combination of the supplied directory name and the file name supplied
   516          * combination of the supplied directory name and the file name supplied
   511          * by the server. If the destination directory does not exist or cannot
   517          * by the server. If the destination directory does not exist or cannot
   512          * be written to, then the response will fail with an {@link IOException}.
   518          * be written to, then the response will fail with an {@link IOException}.
   513          *
   519          *
       
   520          * <p> Security manager permission checks are performed in this factory
       
   521          * method, when a {@code BodyHandler} is created. Care must be taken
       
   522          * that the {@code BodyHandler} is not shared with untrusted code.
       
   523          *
   514          * @param directory the directory to store the file in
   524          * @param directory the directory to store the file in
   515          * @param openOptions open options
   525          * @param openOptions open options used when opening the file
   516          * @return a response body handler
   526          * @return a response body handler
       
   527          * @throws IllegalArgumentException if the given path does not exist,
       
   528          *          is not a directory, is not writable, or if an invalid set
       
   529          *          of open options are specified
   517          * @throws SecurityException If a security manager has been installed
   530          * @throws SecurityException If a security manager has been installed
   518          *          and it denies {@link SecurityManager#checkWrite(String)
   531          *          and it denies {@linkplain SecurityManager#checkRead(String)
   519          *          write access} to the file. The {@link
   532          *          read access} or {@linkplain SecurityManager#checkWrite(String)
   520          *          SecurityManager#checkDelete(String) checkDelete} method is
   533          *          write access} to the directory.
   521          *          invoked to check delete access if the file is opened with
   534          */
   522          *          the {@code DELETE_ON_CLOSE} option.
       
   523          */
       
   524          //####: check if the dir exists and is writable??
       
   525         public static BodyHandler<Path> asFileDownload(Path directory,
   535         public static BodyHandler<Path> asFileDownload(Path directory,
   526                                                        OpenOption... openOptions) {
   536                                                        OpenOption... openOptions) {
   527             Objects.requireNonNull(directory);
   537             Objects.requireNonNull(directory);
   528             List<OpenOption> opts = List.of(openOptions);
   538             List<OpenOption> opts = List.of(openOptions);
       
   539             if (opts.contains(DELETE_ON_CLOSE)) {
       
   540                 throw new IllegalArgumentException("invalid option: " + DELETE_ON_CLOSE);
       
   541             }
       
   542 
   529             SecurityManager sm = System.getSecurityManager();
   543             SecurityManager sm = System.getSecurityManager();
   530             if (sm != null) {
   544             if (sm != null) {
   531                 String fn = pathForSecurityCheck(directory);
   545                 String fn = pathForSecurityCheck(directory);
   532                 sm.checkWrite(fn);
   546                 sm.checkWrite(fn);
   533                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
   547                 sm.checkRead(fn);
   534                     sm.checkDelete(fn);
       
   535                 if (opts.contains(StandardOpenOption.READ))
       
   536                     sm.checkRead(fn);
       
   537             }
   548             }
   538             return new FileDownloadBodyHandler(directory, openOptions);
   549 
       
   550             if (Files.notExists(directory))
       
   551                 throw new IllegalArgumentException("non-existent directory: " + directory);
       
   552             if (!Files.isDirectory(directory))
       
   553                 throw new IllegalArgumentException("not a directory: " + directory);
       
   554             if (!Files.isWritable(directory))
       
   555                 throw new IllegalArgumentException("non-writable directory: " + directory);
       
   556 
       
   557             return new FileDownloadBodyHandler(directory, opts);
   539         }
   558         }
   540 
   559 
   541         /**
   560         /**
   542          * Returns a {@code BodyHandler<InputStream>} that returns a
   561          * Returns a {@code BodyHandler<InputStream>} that returns a
   543          * {@link BodySubscriber BodySubscriber}{@code <InputStream>} obtained
   562          * {@link BodySubscriber BodySubscriber}{@code <InputStream>} obtained
   932             return new ResponseSubscribers.ByteArraySubscriber<>(
   951             return new ResponseSubscribers.ByteArraySubscriber<>(
   933                     Function.identity() // no conversion
   952                     Function.identity() // no conversion
   934             );
   953             );
   935         }
   954         }
   936 
   955 
   937         // no security check
       
   938         private static BodySubscriber<Path> asFileImpl(Path file, OpenOption... openOptions) {
       
   939             return new ResponseSubscribers.PathSubscriber(file, openOptions);
       
   940         }
       
   941 
       
   942         /**
   956         /**
   943          * Returns a {@code BodySubscriber} which stores the response body in a
   957          * Returns a {@code BodySubscriber} which stores the response body in a
   944          * file opened with the given options and name. The file will be opened
   958          * file opened with the given options and name. The file will be opened
   945          * with the given options using {@link FileChannel#open(Path,OpenOption...)
   959          * with the given options using {@link FileChannel#open(Path,OpenOption...)
   946          * FileChannel.open} just before the body is read. Any exception thrown
   960          * FileChannel.open} just before the body is read. Any exception thrown
   949          * BodyHandler) HttpClient::sendAsync} as appropriate.
   963          * BodyHandler) HttpClient::sendAsync} as appropriate.
   950          *
   964          *
   951          * <p> The {@link HttpResponse} using this subscriber is available after
   965          * <p> The {@link HttpResponse} using this subscriber is available after
   952          * the entire response has been read.
   966          * the entire response has been read.
   953          *
   967          *
       
   968          * <p> Security manager permission checks are performed in this factory
       
   969          * method, when a {@code BodySubscriber} is created. Care must be taken
       
   970          * that the {@code BodyHandler} is not shared with untrusted code.
       
   971          *
   954          * @param file the file to store the body in
   972          * @param file the file to store the body in
   955          * @param openOptions the list of options to open the file with
   973          * @param openOptions the list of options to open the file with
   956          * @return a body subscriber
   974          * @return a body subscriber
   957          * @throws SecurityException If a security manager has been installed
   975          * @throws IllegalArgumentException if an invalid set of open options
       
   976          *          are specified
       
   977          * @throws SecurityException if a security manager has been installed
   958          *          and it denies {@link SecurityManager#checkWrite(String)
   978          *          and it denies {@link SecurityManager#checkWrite(String)
   959          *          write access} to the file. The {@link
   979          *          write access} to the file
   960          *          SecurityManager#checkDelete(String) checkDelete} method is
       
   961          *          invoked to check delete access if the file is opened with the
       
   962          *          {@code DELETE_ON_CLOSE} option.
       
   963          */
   980          */
   964         public static BodySubscriber<Path> asFile(Path file, OpenOption... openOptions) {
   981         public static BodySubscriber<Path> asFile(Path file, OpenOption... openOptions) {
   965             Objects.requireNonNull(file);
   982             Objects.requireNonNull(file);
   966             List<OpenOption> opts = List.of(openOptions);
   983             List<OpenOption> opts = List.of(openOptions);
       
   984             if (opts.contains(DELETE_ON_CLOSE) || opts.contains(READ)) {
       
   985                 // these options make no sense, since the FileChannel is not exposed
       
   986                 throw new IllegalArgumentException("invalid openOptions: " + opts);
       
   987             }
       
   988 
   967             SecurityManager sm = System.getSecurityManager();
   989             SecurityManager sm = System.getSecurityManager();
   968             if (sm != null) {
   990             if (sm != null) {
   969                 String fn = pathForSecurityCheck(file);
   991                 String fn = pathForSecurityCheck(file);
   970                 sm.checkWrite(fn);
   992                 sm.checkWrite(fn);
   971                 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE))
       
   972                     sm.checkDelete(fn);
       
   973                 if (opts.contains(StandardOpenOption.READ))
       
   974                     sm.checkRead(fn);
       
   975             }
   993             }
   976             return asFileImpl(file, openOptions);
   994             return new PathSubscriber(file, opts);
   977         }
   995         }
   978 
   996 
   979         /**
   997         /**
   980          * Returns a {@code BodySubscriber} which stores the response body in a
   998          * Returns a {@code BodySubscriber} which stores the response body in a
   981          * file opened with the given name. Has the same effect as calling
   999          * file opened with the given name.
   982          * {@link #asFile(Path, OpenOption...) asFile} with the standard open
  1000          *
   983          * options {@code CREATE} and {@code WRITE}
  1001          * <p> Equivalent to: {@code asFile(file, CREATE, WRITE)}
   984          *
  1002          *
   985          * <p> The {@link HttpResponse} using this subscriber is available after
  1003          * <p> Security manager permission checks are performed in this factory
   986          * the entire response has been read.
  1004          * method, when a {@code BodySubscriber} is created. Care must be taken
       
  1005          * that the {@code BodyHandler} is not shared with untrusted code.
   987          *
  1006          *
   988          * @param file the file to store the body in
  1007          * @param file the file to store the body in
   989          * @return a body subscriber
  1008          * @return a body subscriber
   990          * @throws SecurityException if a security manager has been installed
  1009          * @throws SecurityException if a security manager has been installed
   991          *          and it denies {@link SecurityManager#checkWrite(String)
  1010          *          and it denies {@link SecurityManager#checkWrite(String)
   992          *          write access} to the file
  1011          *          write access} to the file
   993          */
  1012          */
   994         public static BodySubscriber<Path> asFile(Path file) {
  1013         public static BodySubscriber<Path> asFile(Path file) {
   995             return asFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
  1014             return asFile(file, CREATE, WRITE);
   996         }
  1015         }
   997 
  1016 
   998         /**
  1017         /**
   999          * Returns a {@code BodySubscriber} which provides the incoming body
  1018          * Returns a {@code BodySubscriber} which provides the incoming body
  1000          * data to the provided Consumer of {@code Optional<byte[]>}. Each
  1019          * data to the provided Consumer of {@code Optional<byte[]>}. Each