src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java
branchhttp-client-branch
changeset 56257 82a9340bdda6
parent 56138 4f92b988600e
child 56451 9585061fdb04
--- a/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java	Wed Mar 07 13:00:11 2018 +0000
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java	Wed Mar 07 14:06:39 2018 +0000
@@ -27,11 +27,14 @@
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilePermission;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.AccessControlContext;
 import java.security.AccessController;
@@ -217,22 +220,72 @@
         }
     }
 
+    /**
+     * Publishes the content of a given file.
+     *
+     * Privileged actions are performed within a limited doPrivileged that only
+     * asserts the specific, read, file permission that was checked during the
+     * construction of this FilePublisher.
+     */
     public static class FilePublisher implements BodyPublisher  {
+
+        private static final FilePermission[] EMPTY_FILE_PERMISSIONS = new FilePermission[0];
+
         private final File file;
+        private final FilePermission[] filePermissions;
+
+        private static String pathForSecurityCheck(Path path) {
+            return path.toFile().getPath();
+        }
 
-        public FilePublisher(Path name) {
+        /**
+         * Factory for creating FilePublisher.
+         *
+         * Permission checks are performed here before construction of the
+         * FilePublisher. Permission checking and construction are deliberately
+         * and tightly co-located.
+         */
+        public static FilePublisher create(Path path) throws FileNotFoundException {
+            FilePermission filePermission = null;
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                String fn = pathForSecurityCheck(path);
+                FilePermission readPermission = new FilePermission(fn, "read");
+                sm.checkPermission(readPermission);
+                filePermission = readPermission;
+            }
+
+            // existence check must be after permission checks
+            if (Files.notExists(path))
+                throw new FileNotFoundException(path + " not found");
+
+            return new FilePublisher(path, filePermission);
+        }
+
+        private FilePublisher(Path name, FilePermission filePermission) {
+            assert filePermission != null ? filePermission.getActions().equals("read") : true;
             file = name.toFile();
+            this.filePermissions = filePermission == null ? EMPTY_FILE_PERMISSIONS
+                    : new FilePermission[] { filePermission };
         }
 
         @Override
         public void subscribe(Flow.Subscriber<? super ByteBuffer> subscriber) {
             InputStream is;
-            try {
-                PrivilegedExceptionAction<FileInputStream> pa =
-                        () -> new FileInputStream(file);
-                is = AccessController.doPrivileged(pa);
-            } catch (PrivilegedActionException pae) {
-                throw new UncheckedIOException((IOException)pae.getCause());
+            if (System.getSecurityManager() == null) {
+                try {
+                    is = new FileInputStream(file);
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException(ioe);
+                }
+            } else {
+                try {
+                    PrivilegedExceptionAction<FileInputStream> pa =
+                            () -> new FileInputStream(file);
+                    is = AccessController.doPrivileged(pa, null, filePermissions);
+                } catch (PrivilegedActionException pae) {
+                    throw new UncheckedIOException((IOException) pae.getCause());
+                }
             }
             PullPublisher<ByteBuffer> publisher =
                     new PullPublisher<>(() -> new StreamIterator(is));
@@ -241,8 +294,12 @@
 
         @Override
         public long contentLength() {
-            PrivilegedAction<Long> pa = () -> file.length();
-            return AccessController.doPrivileged(pa);
+            if (System.getSecurityManager() == null) {
+                return file.length();
+            } else {
+                PrivilegedAction<Long> pa = () -> file.length();
+                return AccessController.doPrivileged(pa, null, filePermissions);
+            }
         }
     }