-
CSR
-
Resolution: Approved
-
P4
-
behavioral
-
minimal
-
Small change to previously unspecified exceptions being thrown, and a minor rework of non-default file system paths
-
Java API
-
SE
Summary
Specify a file system related constraint in the existing @throws
declarations and the method-level documentation of the following methods:
HttpResponse.BodyHandler::ofFile
HttpResponse.BodySubscriber::ofFile
HttpResponse.BodyHandler::ofFileDownload
Problem
The original specifications of BodyHandler::ofFile
, BodySubscriber::ofFile
and BodyHandler::ofFileDownload
assumed that the given path is associated with the default file system provider or behaves as such, and would fail if this was not the case.
For BodyHandler::ofFile
and BodySubscriber::ofFile
, a fix is proposed to work with other file system path implementations when a security manager is enabled. Accordingly, specification changes should clarify in which case permissions checks are performed and when a SecurityException is thrown, depending on the file system of the given path.
For BodyHandler::ofFileDownoad
, the previous behaviour for a path of a non-default file system was inconsistent: With security manager enabled IOException
was thrown, otherwise UnsupportedOperationException
was thrown. This behaviour was not intended nor documented. A fix is proposed to fail consistently if the given path is not associated with the default file system provider. Specification changes should clarify that a IllegalArgumentException is thrown in this case.
Solution
BodyHandler::ofFile
and BodySubscriber::ofFile
: Specify the case in which permission checks are performed and the conditions of when a SecurityException is thrown, which is only in the case of the default file system provider.
BodyHandler::ofFileDownload
: The proposed change specifies that IllegalArgumentException
is thrown in all cases if the provided path is not of the default file system.
Specification
java.net.http.HttpResponse.BodyHandlers
/**
* Returns a {@code BodyHandler<Path>} that returns a
* {@link BodySubscriber BodySubscriber}{@code <Path>} obtained from
* {@link BodySubscribers#ofFile(Path, OpenOption...)
* BodySubscribers.ofFile(Path,OpenOption...)}.
*
* <p> When the {@code HttpResponse} object is returned, the body has
* been completely written to the file, and {@link #body()} returns a
* reference to its {@link Path}.
*
- * <p> Security manager permission checks are performed in this factory
- * method, when the {@code BodyHandler} is created. Care must be taken
- * that the {@code BodyHandler} is not shared with untrusted code.
+ * <p> In the case of the default file system provider, security manager
+ * permission checks are performed in this factory method, when the
+ * {@code BodyHandler} is created. Otherwise,
+ * {@linkplain FileChannel#open(Path, OpenOption...) permission checks}
+ * may be performed asynchronously against the caller's context
+ * at file access time.
+ * Care must be taken that the {@code BodyHandler} is not shared with
+ * untrusted code.
*
* @param file the file to store the body in
* @param openOptions any options to use when opening/creating the file
* @return a response body handler
* @throws IllegalArgumentException if an invalid set of open options
- * are specified
- * @throws SecurityException If a security manager has been installed
- * and it denies {@linkplain SecurityManager#checkWrite(String)
- * write access} to the file.
+ * are specified
+ * @throws SecurityException in the case of the default file system
+ * provider, and a security manager is installed,
+ * {@link SecurityManager#checkWrite(String) checkWrite}
+ * is invoked to check write access to the given file
*/
public static BodyHandler<Path> ofFile(Path file, OpenOption... openOptions) {
(...)
/**
* Returns a {@code BodyHandler<Path>} that returns a
* {@link BodySubscriber BodySubscriber}{@code <Path>}.
*
* <p> Equivalent to: {@code ofFile(file, CREATE, WRITE)}
*
- * <p> Security manager permission checks are performed in this factory
- * method, when the {@code BodyHandler} is created. Care must be taken
- * that the {@code BodyHandler} is not shared with untrusted code.
+ * <p> In the case of the default file system provider, security manager
+ * permission checks are performed in this factory method, when the
+ * {@code BodyHandler} is created. Otherwise,
+ * {@linkplain FileChannel#open(Path, OpenOption...) permission checks}
+ * may be performed asynchronously against the caller's context
+ * at file access time.
+ * Care must be taken that the {@code BodyHandler} is not shared with
+ * untrusted code.
*
* @param file the file to store the body in
* @return a response body handler
- * @throws SecurityException If a security manager has been installed
- * and it denies {@linkplain SecurityManager#checkWrite(String)
- * write access} to the file.
+ * @throws SecurityException in the case of the default file system
+ * provider, and a security manager is installed,
+ * {@link SecurityManager#checkWrite(String) checkWrite}
+ * is invoked to check write access to the given file
*/
public static BodyHandler<Path> ofFile(Path file) {
(...)
/**
* Returns a {@code BodyHandler<Path>} that returns a
* {@link BodySubscriber BodySubscriber}<{@link Path}>
* where the download directory is specified, but the filename is
* obtained from the {@code Content-Disposition} response header. The
* {@code Content-Disposition} header must specify the <i>attachment</i>
* type and must also contain a <i>filename</i> parameter. If the
* filename specifies multiple path components only the final component
* is used as the filename (with the given directory name).
*
* <p> When the {@code HttpResponse} object is returned, the body has
* been completely written to the file and {@link #body()} returns a
* {@code Path} object for the file. The returned {@code Path} is the
* combination of the supplied directory name and the file name supplied
* by the server. If the destination directory does not exist or cannot
* be written to, then the response will fail with an {@link IOException}.
*
* <p> Security manager permission checks are performed in this factory
* method, when the {@code BodyHandler} is created. Care must be taken
* that the {@code BodyHandler} is not shared with untrusted code.
*
* @param directory the directory to store the file in
* @param openOptions open options used when opening the file
* @return a response body handler
* @throws IllegalArgumentException if the given path does not exist,
- * is not a directory, is not writable, or if an invalid set
- * of open options are specified
+ * is not of the default file system, is not a directory,
+ * is not writable, or if an invalid set of open options
+ * are specified
- * @throws SecurityException If a security manager has been installed
+ * @throws SecurityException in the case of the default file system
+ * provider and a security manager has been installed,
* and it denies
* {@linkplain SecurityManager#checkRead(String) read access}
* to the directory, or it denies
* {@linkplain SecurityManager#checkWrite(String) write access}
* to the directory, or it denies
* {@linkplain SecurityManager#checkWrite(String) write access}
* to the files within the directory.
*/
public static BodyHandler<Path> ofFileDownload(Path directory, OpenOption... openOptions) {
java.net.http.HttpResponse.BodySubscribers
/**
* Returns a {@code BodySubscriber} which stores the response body in a
* file opened with the given options and name. The file will be opened
* with the given options using {@link FileChannel#open(Path,OpenOption...)
* FileChannel.open} just before the body is read. Any exception thrown
* will be returned or thrown from {@link HttpClient#send(HttpRequest,
* BodyHandler) HttpClient::send} or {@link HttpClient#sendAsync(HttpRequest,
* BodyHandler) HttpClient::sendAsync} as appropriate.
*
* <p> The {@link HttpResponse} using this subscriber is available after
* the entire response has been read.
*
- * <p> Security manager permission checks are performed in this factory
- * method, when the {@code BodySubscriber} is created. Care must be taken
- * that the {@code BodyHandler} is not shared with untrusted code.
+ * <p> In the case of the default file system provider, security manager
+ * permission checks are performed in this factory method, when the
+ * {@code BodySubscriber} is created. Otherwise,
+ * {@linkplain FileChannel#open(Path, OpenOption...) permission checks}
+ * may be performed asynchronously against the caller's context
+ * at file access time.
+ * Care must be taken that the {@code BodySubscriber} is not shared with
+ * untrusted code.
*
* @param file the file to store the body in
* @param openOptions the list of options to open the file with
* @return a body subscriber
* @throws IllegalArgumentException if an invalid set of open options
- * are specified
- * @throws SecurityException if a security manager has been installed
- * and it denies {@linkplain SecurityManager#checkWrite(String)
- * write access} to the file
+ * are specified
+ * @throws SecurityException in the case of the default file system
+ * provider, and a security manager is installed,
+ * {@link SecurityManager#checkWrite(String) checkWrite}
+ * is invoked to check write access to the given file
*/
public static BodySubscriber<Path> ofFile(Path file, OpenOption... openOptions) {
(...)
/**
* Returns a {@code BodySubscriber} which stores the response body in a
* file opened with the given name.
*
* <p> Equivalent to: {@code ofFile(file, CREATE, WRITE)}
*
- * <p> Security manager permission checks are performed in this factory
- * method, when the {@code BodySubscriber} is created. Care must be taken
- * that the {@code BodyHandler} is not shared with untrusted code.
+ * <p> In the case of the default file system provider, security manager
+ * permission checks are performed in this factory method, when the
+ * {@code BodySubscriber} is created. Otherwise,
+ * {@linkplain FileChannel#open(Path, OpenOption...) permission checks}
+ * may be performed asynchronously against the caller's context
+ * at file access time.
+ * Care must be taken that the {@code BodySubscriber} is not shared with
+ * untrusted code.
*
* @param file the file to store the body in
* @return a body subscriber
- * @throws SecurityException if a security manager has been installed
- * and it denies {@linkplain SecurityManager#checkWrite(String)
- * write access} to the file
+ * @throws SecurityException in the case of the default file system
+ * provider, and a security manager is installed,
+ * {@link SecurityManager#checkWrite(String) checkWrite}
+ * is invoked to check write access to the given file
*/
public static BodySubscriber<Path> ofFile(Path file) {
- csr of
-
JDK-8237470 HttpResponse.BodySubscriber::ofFile throws UOE with non-default file systems
-
- Closed
-