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; |
|
37 import java.nio.file.OpenOption; |
36 import java.nio.file.OpenOption; |
38 import java.nio.file.Path; |
37 import java.nio.file.Path; |
39 import java.util.List; |
38 import java.util.List; |
40 import java.util.Objects; |
39 import java.util.Objects; |
41 import java.util.Optional; |
40 import java.util.Optional; |
161 * @return HTTP protocol version |
160 * @return HTTP protocol version |
162 */ |
161 */ |
163 public HttpClient.Version version(); |
162 public HttpClient.Version version(); |
164 |
163 |
165 |
164 |
166 private static String pathForSecurityCheck(Path path) { |
|
167 return path.toFile().getPath(); |
|
168 } |
|
169 |
|
170 |
|
171 /** |
165 /** |
172 * A handler for response bodies. The class {@link BodyHandlers BodyHandlers} |
166 * A handler for response bodies. The class {@link BodyHandlers BodyHandlers} |
173 * provides implementations of many common body handlers. |
167 * provides implementations of many common body handlers. |
174 * |
168 * |
175 * <p> The {@code BodyHandler} interface allows inspection of the response |
169 * <p> The {@code BodyHandler} interface allows inspection of the response |
502 List<OpenOption> opts = List.of(openOptions); |
496 List<OpenOption> opts = List.of(openOptions); |
503 if (opts.contains(DELETE_ON_CLOSE) || opts.contains(READ)) { |
497 if (opts.contains(DELETE_ON_CLOSE) || opts.contains(READ)) { |
504 // these options make no sense, since the FileChannel is not exposed |
498 // these options make no sense, since the FileChannel is not exposed |
505 throw new IllegalArgumentException("invalid openOptions: " + opts); |
499 throw new IllegalArgumentException("invalid openOptions: " + opts); |
506 } |
500 } |
507 |
501 return PathBodyHandler.create(file, opts); |
508 SecurityManager sm = System.getSecurityManager(); |
|
509 if (sm != null) { |
|
510 String fn = pathForSecurityCheck(file); |
|
511 sm.checkWrite(fn); |
|
512 } |
|
513 return new PathBodyHandler(file, opts); |
|
514 } |
502 } |
515 |
503 |
516 /** |
504 /** |
517 * Returns a {@code BodyHandler<Path>} that returns a |
505 * Returns a {@code BodyHandler<Path>} that returns a |
518 * {@link BodySubscriber BodySubscriber}{@code <Path>}. |
506 * {@link BodySubscriber BodySubscriber}{@code <Path>}. |
559 * @return a response body handler |
547 * @return a response body handler |
560 * @throws IllegalArgumentException if the given path does not exist, |
548 * @throws IllegalArgumentException if the given path does not exist, |
561 * is not a directory, is not writable, or if an invalid set |
549 * is not a directory, is not writable, or if an invalid set |
562 * of open options are specified |
550 * of open options are specified |
563 * @throws SecurityException If a security manager has been installed |
551 * @throws SecurityException If a security manager has been installed |
564 * and it denies {@linkplain SecurityManager#checkRead(String) |
552 * and it denies |
565 * read access} or {@linkplain SecurityManager#checkWrite(String) |
553 * {@linkplain SecurityManager#checkRead(String) read access} |
566 * write access} to the directory. |
554 * to the directory, or it denies |
|
555 * {@linkplain SecurityManager#checkWrite(String) write access} |
|
556 * to the directory, or it denies |
|
557 * {@linkplain SecurityManager#checkWrite(String) write access} |
|
558 * to the files within the directory. |
567 */ |
559 */ |
568 public static BodyHandler<Path> ofFileDownload(Path directory, |
560 public static BodyHandler<Path> ofFileDownload(Path directory, |
569 OpenOption... openOptions) { |
561 OpenOption... openOptions) { |
570 Objects.requireNonNull(directory); |
562 Objects.requireNonNull(directory); |
571 List<OpenOption> opts = List.of(openOptions); |
563 List<OpenOption> opts = List.of(openOptions); |
572 if (opts.contains(DELETE_ON_CLOSE)) { |
564 if (opts.contains(DELETE_ON_CLOSE)) { |
573 throw new IllegalArgumentException("invalid option: " + DELETE_ON_CLOSE); |
565 throw new IllegalArgumentException("invalid option: " + DELETE_ON_CLOSE); |
574 } |
566 } |
575 |
567 return FileDownloadBodyHandler.create(directory, opts); |
576 SecurityManager sm = System.getSecurityManager(); |
|
577 if (sm != null) { |
|
578 String fn = pathForSecurityCheck(directory); |
|
579 sm.checkWrite(fn); |
|
580 sm.checkRead(fn); |
|
581 } |
|
582 |
|
583 if (Files.notExists(directory)) |
|
584 throw new IllegalArgumentException("non-existent directory: " + directory); |
|
585 if (!Files.isDirectory(directory)) |
|
586 throw new IllegalArgumentException("not a directory: " + directory); |
|
587 if (!Files.isWritable(directory)) |
|
588 throw new IllegalArgumentException("non-writable directory: " + directory); |
|
589 |
|
590 return new FileDownloadBodyHandler(directory, opts); |
|
591 } |
568 } |
592 |
569 |
593 /** |
570 /** |
594 * Returns a {@code BodyHandler<InputStream>} that returns a |
571 * Returns a {@code BodyHandler<InputStream>} that returns a |
595 * {@link BodySubscriber BodySubscriber}{@code <InputStream>} obtained from |
572 * {@link BodySubscriber BodySubscriber}{@code <InputStream>} obtained from |
1056 List<OpenOption> opts = List.of(openOptions); |
1033 List<OpenOption> opts = List.of(openOptions); |
1057 if (opts.contains(DELETE_ON_CLOSE) || opts.contains(READ)) { |
1034 if (opts.contains(DELETE_ON_CLOSE) || opts.contains(READ)) { |
1058 // these options make no sense, since the FileChannel is not exposed |
1035 // these options make no sense, since the FileChannel is not exposed |
1059 throw new IllegalArgumentException("invalid openOptions: " + opts); |
1036 throw new IllegalArgumentException("invalid openOptions: " + opts); |
1060 } |
1037 } |
1061 |
1038 return PathSubscriber.create(file, opts); |
1062 SecurityManager sm = System.getSecurityManager(); |
|
1063 if (sm != null) { |
|
1064 String fn = pathForSecurityCheck(file); |
|
1065 sm.checkWrite(fn); |
|
1066 } |
|
1067 return new PathSubscriber(file, opts); |
|
1068 } |
1039 } |
1069 |
1040 |
1070 /** |
1041 /** |
1071 * Returns a {@code BodySubscriber} which stores the response body in a |
1042 * Returns a {@code BodySubscriber} which stores the response body in a |
1072 * file opened with the given name. |
1043 * file opened with the given name. |