29 import java.io.UncheckedIOException; |
29 import java.io.UncheckedIOException; |
30 import java.net.URI; |
30 import java.net.URI; |
31 import java.nio.file.OpenOption; |
31 import java.nio.file.OpenOption; |
32 import java.nio.file.Path; |
32 import java.nio.file.Path; |
33 import java.nio.file.Paths; |
33 import java.nio.file.Paths; |
34 import java.security.AccessControlContext; |
34 import java.nio.file.StandardOpenOption; |
35 import java.util.List; |
35 import java.util.List; |
36 import java.util.concurrent.CompletableFuture; |
36 import java.util.concurrent.CompletableFuture; |
37 import java.util.concurrent.ConcurrentMap; |
37 import java.util.concurrent.ConcurrentMap; |
38 import java.util.function.Function; |
38 import java.util.function.Function; |
39 import java.net.http.HttpHeaders; |
39 import java.net.http.HttpHeaders; |
50 |
50 |
51 private ResponseBodyHandlers() { } |
51 private ResponseBodyHandlers() { } |
52 |
52 |
53 /** |
53 /** |
54 * A Path body handler. |
54 * A Path body handler. |
55 * |
|
56 * Note: Exists mainly too allow setting of the senders ACC post creation of |
|
57 * the handler. |
|
58 */ |
55 */ |
59 public static class PathBodyHandler implements UntrustedBodyHandler<Path> { |
56 public static class PathBodyHandler implements BodyHandler<Path>{ |
60 private final Path file; |
57 private final Path file; |
61 private final OpenOption[]openOptions; |
58 private final List<OpenOption> openOptions; |
62 private volatile AccessControlContext acc; |
59 |
63 |
60 public PathBodyHandler(Path file, List<OpenOption> openOptions) { |
64 public PathBodyHandler(Path file, OpenOption... openOptions) { |
|
65 this.file = file; |
61 this.file = file; |
66 this.openOptions = openOptions; |
62 this.openOptions = openOptions; |
67 } |
63 } |
68 |
64 |
69 @Override |
65 @Override |
70 public void setAccessControlContext(AccessControlContext acc) { |
|
71 this.acc = acc; |
|
72 } |
|
73 |
|
74 @Override |
|
75 public BodySubscriber<Path> apply(int statusCode, HttpHeaders headers) { |
66 public BodySubscriber<Path> apply(int statusCode, HttpHeaders headers) { |
76 PathSubscriber bs = (PathSubscriber) asFileImpl(file, openOptions); |
67 return new PathSubscriber(file, openOptions); |
77 bs.setAccessControlContext(acc); |
|
78 return bs; |
|
79 } |
68 } |
80 } |
69 } |
81 |
70 |
82 /** With push promise Map implementation */ |
71 /** With push promise Map implementation */ |
83 public static class PushPromisesHandlerWithMap<T> |
72 public static class PushPromisesHandlerWithMap<T> |
123 acceptor.apply(pushPromiseHandler.apply(pushRequest)); |
112 acceptor.apply(pushPromiseHandler.apply(pushRequest)); |
124 pushPromisesMap.put(pushRequest, cf); |
113 pushPromisesMap.put(pushRequest, cf); |
125 } |
114 } |
126 } |
115 } |
127 |
116 |
128 // Similar to Path body handler, but for file download. Supports setting ACC. |
117 // Similar to Path body handler, but for file download. |
129 public static class FileDownloadBodyHandler implements UntrustedBodyHandler<Path> { |
118 public static class FileDownloadBodyHandler implements BodyHandler<Path> { |
130 private final Path directory; |
119 private final Path directory; |
131 private final OpenOption[] openOptions; |
120 private final List<OpenOption> openOptions; |
132 private volatile AccessControlContext acc; |
121 |
133 |
122 public FileDownloadBodyHandler(Path directory, List<OpenOption> openOptions) { |
134 public FileDownloadBodyHandler(Path directory, OpenOption... openOptions) { |
|
135 this.directory = directory; |
123 this.directory = directory; |
136 this.openOptions = openOptions; |
124 this.openOptions = openOptions; |
137 } |
|
138 |
|
139 @Override |
|
140 public void setAccessControlContext(AccessControlContext acc) { |
|
141 this.acc = acc; |
|
142 } |
125 } |
143 |
126 |
144 /** The "attachment" disposition-type and separator. */ |
127 /** The "attachment" disposition-type and separator. */ |
145 static final String DISPOSITION_TYPE = "attachment;"; |
128 static final String DISPOSITION_TYPE = "attachment;"; |
146 |
129 |
219 if (!file.startsWith(directory)) { |
202 if (!file.startsWith(directory)) { |
220 throw unchecked(statusCode, headers, |
203 throw unchecked(statusCode, headers, |
221 "Resulting file, " + file.toString() + ", outside of given directory"); |
204 "Resulting file, " + file.toString() + ", outside of given directory"); |
222 } |
205 } |
223 |
206 |
224 PathSubscriber bs = (PathSubscriber)asFileImpl(file, openOptions); |
207 return new PathSubscriber(file, openOptions); |
225 bs.setAccessControlContext(acc); |
208 } |
226 return bs; |
|
227 } |
|
228 } |
|
229 |
|
230 // no security check |
|
231 private static BodySubscriber<Path> asFileImpl(Path file, OpenOption... openOptions) { |
|
232 return new ResponseSubscribers.PathSubscriber(file, openOptions); |
|
233 } |
209 } |
234 } |
210 } |