src/java.net.http/share/classes/jdk/internal/net/http/ResponseSubscribers.java
branchhttp-client-branch
changeset 56257 82a9340bdda6
parent 56159 039ab5a71a5c
child 56405 3642d0ef7755
equal deleted inserted replaced
56256:0fe17c3f9b4f 56257:82a9340bdda6
    24  */
    24  */
    25 
    25 
    26 package jdk.internal.net.http;
    26 package jdk.internal.net.http;
    27 
    27 
    28 import java.io.BufferedReader;
    28 import java.io.BufferedReader;
       
    29 import java.io.FilePermission;
    29 import java.io.IOException;
    30 import java.io.IOException;
    30 import java.io.InputStream;
    31 import java.io.InputStream;
    31 import java.io.InputStreamReader;
    32 import java.io.InputStreamReader;
    32 import java.lang.System.Logger.Level;
    33 import java.lang.System.Logger.Level;
    33 import java.nio.ByteBuffer;
    34 import java.nio.ByteBuffer;
   107             result.complete(null);
   108             result.complete(null);
   108         }
   109         }
   109 
   110 
   110     }
   111     }
   111 
   112 
       
   113     /**
       
   114      * A Subscriber that writes the flow of data to a given file.
       
   115      *
       
   116      * Privileged actions are performed within a limited doPrivileged that only
       
   117      * asserts the specific, write, file permissions that were checked during
       
   118      * the construction of this PathSubscriber.
       
   119      */
   112     public static class PathSubscriber implements BodySubscriber<Path> {
   120     public static class PathSubscriber implements BodySubscriber<Path> {
   113 
   121 
       
   122         private static final FilePermission[] EMPTY_FILE_PERMISSIONS = new FilePermission[0];
       
   123 
   114         private final Path file;
   124         private final Path file;
       
   125         private final OpenOption[] options;
       
   126         private final FilePermission[] filePermissions;
   115         private final CompletableFuture<Path> result = new MinimalFuture<>();
   127         private final CompletableFuture<Path> result = new MinimalFuture<>();
   116         private final OpenOption[] options;
       
   117 
   128 
   118         private volatile Flow.Subscription subscription;
   129         private volatile Flow.Subscription subscription;
   119         private volatile FileChannel out;
   130         private volatile FileChannel out;
   120 
   131 
   121         public PathSubscriber(Path file, List<OpenOption> options) {
   132         private static final String pathForSecurityCheck(Path path) {
       
   133             return path.toFile().getPath();
       
   134         }
       
   135 
       
   136         /**
       
   137          * Factory for creating PathSubscriber.
       
   138          *
       
   139          * Permission checks are performed here before construction of the
       
   140          * PathSubscriber. Permission checking and construction are deliberately
       
   141          * and tightly co-located.
       
   142          */
       
   143         public static PathSubscriber create(Path file,
       
   144                                             List<OpenOption> options) {
       
   145             FilePermission filePermission = null;
       
   146             SecurityManager sm = System.getSecurityManager();
       
   147             if (sm != null) {
       
   148                 String fn = pathForSecurityCheck(file);
       
   149                 FilePermission writePermission = new FilePermission(fn, "write");
       
   150                 sm.checkPermission(writePermission);
       
   151                 filePermission = writePermission;
       
   152             }
       
   153             return new PathSubscriber(file, options, filePermission);
       
   154         }
       
   155 
       
   156         // pp so handler implementations in the same package can construct
       
   157         /*package-private*/ PathSubscriber(Path file,
       
   158                                            List<OpenOption> options,
       
   159                                            FilePermission... filePermissions) {
   122             this.file = file;
   160             this.file = file;
   123             this.options = options.stream().toArray(OpenOption[]::new);
   161             this.options = options.stream().toArray(OpenOption[]::new);
       
   162             this.filePermissions =
       
   163                     filePermissions == null ? EMPTY_FILE_PERMISSIONS : filePermissions;
   124         }
   164         }
   125 
   165 
   126         @Override
   166         @Override
   127         public void onSubscribe(Flow.Subscription subscription) {
   167         public void onSubscribe(Flow.Subscription subscription) {
   128             this.subscription = subscription;
   168             this.subscription = subscription;
   129             try {
   169             if (System.getSecurityManager() == null) {
   130                 PrivilegedExceptionAction<FileChannel> pa =
   170                 try {
   131                         () -> FileChannel.open(file, options);
   171                     out = FileChannel.open(file, options);
   132                 out = AccessController.doPrivileged(pa);
   172                 } catch (IOException ioe) {
   133             } catch (PrivilegedActionException pae) {
   173                     result.completeExceptionally(ioe);
   134                 Throwable t = pae.getCause() != null ? pae.getCause() : pae;
   174                     return;
   135                 result.completeExceptionally(t);
   175                 }
   136                 subscription.cancel();
   176             } else {
   137                 return;
   177                 try {
       
   178                     PrivilegedExceptionAction<FileChannel> pa =
       
   179                             () -> FileChannel.open(file, options);
       
   180                     out = AccessController.doPrivileged(pa, null, filePermissions);
       
   181                 } catch (PrivilegedActionException pae) {
       
   182                     Throwable t = pae.getCause() != null ? pae.getCause() : pae;
       
   183                     result.completeExceptionally(t);
       
   184                     subscription.cancel();
       
   185                     return;
       
   186                 }
   138             }
   187             }
   139             subscription.request(1);
   188             subscription.request(1);
   140         }
   189         }
   141 
   190 
   142         @Override
   191         @Override