|
20 | 20 |
|
21 | 21 | package com.teamdev.jxbrowser.examples.interceptor; |
22 | 22 |
|
23 | | -import static com.google.common.base.Preconditions.checkNotNull; |
24 | | -import static com.teamdev.jxbrowser.examples.interceptor.MimeTypes.mimeType; |
25 | | -import static com.teamdev.jxbrowser.internal.string.StringPreconditions.checkNotNullEmptyOrBlank; |
26 | | -import static com.teamdev.jxbrowser.logging.Logger.error; |
27 | | -import static com.teamdev.jxbrowser.net.HttpStatus.INTERNAL_SERVER_ERROR; |
28 | | -import static com.teamdev.jxbrowser.net.HttpStatus.NOT_FOUND; |
29 | | -import static com.teamdev.jxbrowser.net.HttpStatus.OK; |
30 | | -import static java.util.Collections.emptyList; |
31 | | -import static java.util.Collections.singletonList; |
| 23 | +import static java.nio.file.Files.exists; |
| 24 | +import static java.nio.file.Files.isDirectory; |
32 | 25 |
|
33 | | -import com.teamdev.jxbrowser.net.HttpHeader; |
34 | | -import com.teamdev.jxbrowser.net.HttpStatus; |
35 | | -import com.teamdev.jxbrowser.net.UrlRequestJob; |
36 | | -import com.teamdev.jxbrowser.net.callback.InterceptUrlRequestCallback; |
37 | 26 | import java.io.FileInputStream; |
38 | 27 | import java.io.IOException; |
39 | | -import java.net.URI; |
40 | | -import java.nio.file.Files; |
| 28 | +import java.io.InputStream; |
41 | 29 | import java.nio.file.Path; |
42 | | -import java.nio.file.Paths; |
43 | | -import java.util.Arrays; |
44 | | -import java.util.List; |
45 | 30 |
|
46 | 31 | /** |
47 | | - * An interceptor that treats every URL under the given domain as a path to the file on disk and |
48 | | - * loads it. |
| 32 | + * An interceptor that treats every URL under the given domain as a path to a |
| 33 | + * file on disk and loads it. |
49 | 34 | * |
50 | | - * <p>The interceptor is configured with the domain name and the content directory. For every |
51 | | - * request, it takes the path component of the URL and looks for it in the content directory. That |
52 | | - * means a request to {@code example.com/docs/index.html} will load {@code docs/index.html} file |
53 | | - * from the content directory. The mime type of the file is derived automatically. |
| 35 | + * <p>The interceptor is configured with the domain name and the content |
| 36 | + * directory. For every request, it takes the path component of the URL and |
| 37 | + * looks for it in the content directory. That means a request to |
| 38 | + * {@code example.com/docs/index.html} will load {@code docs/index.html} file |
| 39 | + * from the content directory. The MIME type of the file is derived |
| 40 | + * automatically. |
54 | 41 | * |
55 | 42 | * <p>This interceptor responds with the following status codes: |
56 | 43 | * |
57 | 44 | * <ul> |
58 | 45 | * <li><b>200 OK</b> - the file was found and read properly. |
59 | 46 | * In this case, the {@code Content-Type} header is sent.</li> |
60 | | - * <li><b>404 Not Found</b> - the file could not be found due to an invalid path.</li> |
| 47 | + * <li><b>404 Not Found</b> - the file could not be found.</li> |
61 | 48 | * <li><b>500 Internal Server Error</b> - couldn't read the file.</li> |
62 | 49 | * </ul> |
63 | 50 | * |
64 | | - * <p>This interceptor considers only the path component of the URL request. It ignores request |
65 | | - * parameters and headers. |
66 | | - * |
67 | | - * <p>Note: using this interceptor can reduce performance since it processes all incoming |
68 | | - * traffic under the scheme. |
| 51 | + * <p>This interceptor considers only the path component of the URL request. |
| 52 | + * It ignores request parameters and headers. |
69 | 53 | */ |
70 | | -public final class DomainToFolderInterceptor implements InterceptUrlRequestCallback { |
71 | | - |
72 | | - private static final String CONTENT_TYPE = "Content-Type"; |
| 54 | +public final class DomainToFolderInterceptor extends DomainContentInterceptor { |
73 | 55 |
|
74 | | - private final String domain; |
75 | 56 | private final Path contentRoot; |
76 | 57 |
|
77 | | - private DomainToFolderInterceptor(String domain, Path contentRoot) { |
78 | | - this.domain = domain; |
79 | | - this.contentRoot = contentRoot; |
80 | | - } |
81 | | - |
82 | 58 | /** |
83 | | - * Creates a URL interceptor for the given domain to load files from the given directory. |
| 59 | + * Creates a URL interceptor for the given domain to load files from the |
| 60 | + * given directory. |
84 | 61 | * |
85 | 62 | * @param domain a domain name to intercept |
86 | 63 | * @param contentRoot a path to the directory with files to load |
87 | 64 | */ |
88 | | - public static DomainToFolderInterceptor create(String domain, Path contentRoot) { |
89 | | - checkNotNull(contentRoot); |
90 | | - checkNotNullEmptyOrBlank(domain); |
91 | | - return new DomainToFolderInterceptor(domain, contentRoot.toAbsolutePath()); |
| 65 | + public DomainToFolderInterceptor(String domain, Path contentRoot) { |
| 66 | + super(domain); |
| 67 | + this.contentRoot = contentRoot.toAbsolutePath(); |
92 | 68 | } |
93 | 69 |
|
| 70 | + /** |
| 71 | + * Resolves the requested path to a file and opens it. |
| 72 | + */ |
94 | 73 | @Override |
95 | | - public Response on(Params params) { |
96 | | - URI uri = URI.create(params.urlRequest().url()); |
97 | | - if (shouldNotBeIntercepted(uri)) { |
98 | | - return Response.proceed(); |
99 | | - } |
100 | | - Path filePath = getPathOnDisk(uri); |
101 | | - UrlRequestJob job; |
102 | | - if (fileExists(filePath)) { |
103 | | - HttpHeader contentType = getContentType(filePath); |
104 | | - job = createJob(params, OK, singletonList(contentType)); |
105 | | - try { |
106 | | - readFile(filePath, job); |
107 | | - } catch (IOException e) { |
108 | | - error("Failed to read file {0}", e, filePath); |
109 | | - job = createJob(params, INTERNAL_SERVER_ERROR); |
110 | | - } |
111 | | - } else { |
112 | | - job = createJob(params, NOT_FOUND); |
113 | | - } |
114 | | - job.complete(); |
115 | | - return Response.intercept(job); |
116 | | - } |
117 | | - |
118 | | - private boolean shouldNotBeIntercepted(URI uri) { |
119 | | - return !uri.getHost().equals(domain); |
120 | | - } |
121 | | - |
122 | | - private Path getPathOnDisk(URI uri) { |
123 | | - return Paths.get(contentRoot.toString(), uri.getPath()); |
124 | | - } |
125 | | - |
126 | | - private boolean fileExists(Path filePath) { |
127 | | - return Files.exists(filePath) && !Files.isDirectory(filePath); |
128 | | - } |
129 | | - |
130 | | - private HttpHeader getContentType(Path file) { |
131 | | - return HttpHeader.of(CONTENT_TYPE, mimeType(file).value()); |
132 | | - } |
133 | | - |
134 | | - private UrlRequestJob createJob(Params params, |
135 | | - HttpStatus httpStatus, |
136 | | - List<HttpHeader> httpHeaders) { |
137 | | - UrlRequestJob.Options.Builder builder = UrlRequestJob.Options.newBuilder(httpStatus); |
138 | | - httpHeaders.forEach(builder::addHttpHeader); |
139 | | - return params.newUrlRequestJob(builder.build()); |
140 | | - } |
141 | | - |
142 | | - private UrlRequestJob createJob(Params params, HttpStatus httpStatus) { |
143 | | - return createJob(params, httpStatus, emptyList()); |
144 | | - } |
145 | | - |
146 | | - private void readFile(Path filePath, UrlRequestJob job) throws IOException { |
147 | | - try (FileInputStream stream = new FileInputStream(filePath.toFile())) { |
148 | | - byte[] buffer = new byte[4096]; |
149 | | - int bytesRead; |
150 | | - while ((bytesRead = stream.read(buffer)) > 0) { |
151 | | - if (bytesRead != buffer.length) { |
152 | | - buffer = Arrays.copyOf(buffer, bytesRead); |
153 | | - } |
154 | | - job.write(buffer); |
155 | | - } |
| 74 | + protected InputStream openContent(String path) throws IOException { |
| 75 | + var filePath = contentRoot.resolve(path); |
| 76 | + if (exists(filePath) && !isDirectory(filePath)) { |
| 77 | + return new FileInputStream(filePath.toFile()); |
156 | 78 | } |
| 79 | + return null; |
157 | 80 | } |
158 | 81 | } |
0 commit comments