Skip to content
This repository was archived by the owner on Sep 19, 2021. It is now read-only.

Commit 6f39027

Browse files
Add expiration time parameter
1 parent 49c306e commit 6f39027

File tree

7 files changed

+64
-34
lines changed

7 files changed

+64
-34
lines changed

src/main/java/com/qwazr/webapps/StaticFileServlet.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2017 Emmanuel Keller / QWAZR
2+
* Copyright 2015-2020 Emmanuel Keller / QWAZR
33
* <p>
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616
package com.qwazr.webapps;
1717

1818
import com.qwazr.server.ServerException;
19+
import com.qwazr.utils.HashUtils;
1920
import org.apache.commons.io.IOUtils;
2021

2122
import javax.activation.MimetypesFileTypeMap;
@@ -33,9 +34,12 @@ public class StaticFileServlet extends HttpServlet {
3334

3435
private final MimetypesFileTypeMap mimeTypeMap;
3536
private final Path staticPath;
37+
private final int expirationSecTime;
3638

37-
public StaticFileServlet(final MimetypesFileTypeMap mimeTypeMap, final Path staticPath) {
39+
public StaticFileServlet(final MimetypesFileTypeMap mimeTypeMap, final Path staticPath,
40+
final int expirationSecTime) {
3841
this.mimeTypeMap = mimeTypeMap;
42+
this.expirationSecTime = expirationSecTime;
3943
if (staticPath == null)
4044
throw new ServerException("The path is empty");
4145
if (!Files.exists(staticPath))
@@ -71,16 +75,20 @@ private File handleFile(final HttpServletRequest request, final HttpServletRespo
7175
return staticFile.toFile();
7276
}
7377

74-
final static void head(final Long length, final String type, final Long lastModified,
75-
final HttpServletResponse response) {
78+
static void head(final String fileName, final Long length, final String type, final Long lastModified,
79+
final long expirationSecTime, final HttpServletResponse response) {
7680
if (type != null)
7781
response.setContentType(type);
7882
if (length != null)
7983
response.setContentLengthLong(length);
80-
if (lastModified != null)
84+
if (lastModified != null) {
8185
response.setDateHeader("Last-Modified", lastModified);
82-
response.setHeader("Cache-Control", "max-age=86400");
83-
response.setDateHeader("Expires", System.currentTimeMillis() + 86400 * 1000);
86+
if (fileName != null)
87+
response.setHeader("ETag",
88+
HashUtils.getMurmur3Hash32Hex(fileName) + '-' + Long.toHexString(lastModified));
89+
}
90+
response.setHeader("Cache-Control", "max-age=" + expirationSecTime);
91+
response.setDateHeader("Expires", System.currentTimeMillis() + expirationSecTime * 1000);
8492
}
8593

8694
@Override
@@ -89,7 +97,7 @@ protected void doHead(final HttpServletRequest request, final HttpServletRespons
8997
if (staticFile == null)
9098
return;
9199
final String type = mimeTypeMap.getContentType(staticFile);
92-
head(staticFile.length(), type, staticFile.lastModified(), response);
100+
head(staticFile.toString(), staticFile.length(), type, staticFile.lastModified(), expirationSecTime, response);
93101
}
94102

95103
@Override
@@ -98,7 +106,7 @@ protected void doGet(final HttpServletRequest request, final HttpServletResponse
98106
if (staticFile == null)
99107
return;
100108
final String type = mimeTypeMap.getContentType(staticFile);
101-
head(staticFile.length(), type, staticFile.lastModified(), response);
109+
head(staticFile.toString(), staticFile.length(), type, staticFile.lastModified(), expirationSecTime, response);
102110
try (final FileInputStream fis = new FileInputStream(staticFile)) {
103111
final ServletOutputStream out = response.getOutputStream();
104112
IOUtils.copy(fis, out);

src/main/java/com/qwazr/webapps/StaticResourceServlet.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2016 Emmanuel Keller / QWAZR
2+
* Copyright 2015-2020 Emmanuel Keller / QWAZR
33
* <p>
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,11 +32,15 @@ public class StaticResourceServlet extends HttpServlet {
3232

3333
private final MimetypesFileTypeMap mimeTypeMap;
3434

35-
public StaticResourceServlet(final String resourcePrefix, final MimetypesFileTypeMap mimeTypeMap) {
35+
private final int expirationTimeSec;
36+
37+
public StaticResourceServlet(final String resourcePrefix, final MimetypesFileTypeMap mimeTypeMap,
38+
final int expirationTimeSec) {
3639
this.resourcePrefix = resourcePrefix;
3740
this.mimeTypeMap = Objects.requireNonNull(mimeTypeMap, "The mimeTypeMap is missing");
41+
this.expirationTimeSec = expirationTimeSec;
3842
}
39-
43+
4044
private String getResourcePath(final HttpServletRequest request) {
4145
final String path = request.getPathInfo();
4246
return path == null ? resourcePrefix : resourcePrefix + path;
@@ -55,7 +59,7 @@ final protected void doHead(final HttpServletRequest request, final HttpServletR
5559
final String resourcePath = getResourcePath(request);
5660
try (final InputStream input = findResource(resourcePath)) {
5761
final String type = mimeTypeMap.getContentType(resourcePath);
58-
StaticFileServlet.head(null, type, null, response);
62+
StaticFileServlet.head(null, null, type, null, expirationTimeSec, response);
5963
} catch (FileNotFoundException e) {
6064
response.sendError(404, e.getMessage());
6165
}
@@ -67,7 +71,7 @@ final protected void doGet(final HttpServletRequest request, final HttpServletRe
6771
final String resourcePath = getResourcePath(request);
6872
try (final InputStream input = findResource(resourcePath)) {
6973
final String type = mimeTypeMap.getContentType(resourcePath);
70-
StaticFileServlet.head(null, type, null, response);
74+
StaticFileServlet.head(null, null, type, null, expirationTimeSec, response);
7175
IOUtils.copy(input, response.getOutputStream());
7276
} catch (FileNotFoundException e) {
7377
response.sendError(404, e.getMessage());

src/main/java/com/qwazr/webapps/WebappHttpResponse.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,11 @@ public PrintWriter getWriter() throws IOException {
5252
return response.getWriter();
5353
}
5454

55-
public void sendFile(File file) throws IOException {
56-
FileInputStream fis = new FileInputStream(file);
57-
try {
58-
BufferedInputStream bis = new BufferedInputStream(fis);
59-
try {
55+
public void sendFile(final File file) throws IOException {
56+
try (final FileInputStream fis = new FileInputStream(file)) {
57+
try (final BufferedInputStream bis = new BufferedInputStream(fis)) {
6058
IOUtils.copy(bis, response.getOutputStream());
61-
} finally {
62-
IOUtils.closeQuietly(bis);
6359
}
64-
} finally {
65-
IOUtils.closeQuietly(fis);
6660
}
6761
}
6862

src/main/java/com/qwazr/webapps/WebappManager.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858

5959
public class WebappManager {
6060

61+
public final static int DEFAULT_EXPIRATION_TIME = 86400;
62+
6163
public final static List<Class<?>> SWAGGER_CLASSES =
6264
Collections.unmodifiableList(Collections.singletonList(OpenApiResource.class));
6365

@@ -122,7 +124,7 @@ public Builder webappDefinition(final java.nio.file.Path parentDirectory,
122124
if (finalFilePath.contains(".") && !finalFilePath.contains("/"))
123125
registerStaticServlet(urlPath, finalFilePath);
124126
else
125-
registerStaticServlet(urlPath, parentDirectory.resolve(finalFilePath));
127+
registerStaticServlet(urlPath, parentDirectory.resolve(finalFilePath), DEFAULT_EXPIRATION_TIME);
126128
});
127129

128130
// Load the listeners
@@ -210,32 +212,42 @@ private synchronized MimetypesFileTypeMap getMimeTypeMap() {
210212
return mimeTypeMap;
211213
}
212214

213-
public Builder registerStaticServlet(final String urlPath, final String resourcePath) {
215+
public Builder registerStaticServlet(final String urlPath, final String resourcePath,
216+
final int expirationSecTime) {
214217
final ServletInfo servletInfo =
215218
new ServletInfo(StaticResourceServlet.class.getName() + '@' + urlPath, StaticResourceServlet.class,
216219
GenericFactory.fromInstance(
217220
new StaticResourceServlet('/' + StringUtils.replaceChars(resourcePath, '.', '/'),
218-
getMimeTypeMap()))).addMapping(urlPath);
221+
getMimeTypeMap(), expirationSecTime))).addMapping(urlPath);
219222
context.servlet(servletInfo);
220223
return this;
221224
}
222225

223-
public Builder registerStaticServlet(final String urlPath, final java.nio.file.Path staticsPath) {
226+
public Builder registerStaticServlet(final String urlPath, final String resourcePath) {
227+
return registerStaticServlet(urlPath, resourcePath, DEFAULT_EXPIRATION_TIME);
228+
}
229+
230+
public Builder registerStaticServlet(final String urlPath, final java.nio.file.Path staticsPath,
231+
final int expirationSecTime) {
224232
final ServletInfo servletInfo =
225233
new ServletInfo(StaticFileServlet.class.getName() + '@' + urlPath, StaticFileServlet.class,
226-
GenericFactory.fromInstance(
227-
new StaticFileServlet(getMimeTypeMap(), staticsPath))).addMapping(urlPath);
234+
GenericFactory.fromInstance(new StaticFileServlet(getMimeTypeMap(), staticsPath,
235+
expirationSecTime))).addMapping(urlPath);
228236
context.servlet(servletInfo);
229237
return this;
230238
}
231239

232-
private ServletInfo getDefaultFaviconServlet() {
240+
private ServletInfo getDefaultFaviconServlet(int expirationTimeSec) {
233241
return new ServletInfo(StaticResourceServlet.class.getName() + '@' + FAVICON_PATH,
234242
StaticResourceServlet.class, GenericFactory.fromInstance(
235-
new StaticResourceServlet("/com/qwazr/webapps/favicon.ico", getMimeTypeMap()))).
243+
new StaticResourceServlet("/com/qwazr/webapps/favicon.ico", getMimeTypeMap(), expirationTimeSec))).
236244
addMapping(FAVICON_PATH);
237245
}
238246

247+
private ServletInfo getDefaultFaviconServlet() {
248+
return getDefaultFaviconServlet(DEFAULT_EXPIRATION_TIME);
249+
}
250+
239251
private Builder registerController(final String urlPath, final java.nio.file.Path parentDirectory,
240252
final String filePath) {
241253
try {

src/test/java/com/qwazr/webapps/test/FullTest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
import javax.ws.rs.core.Response;
3434
import java.io.IOException;
3535

36+
import static org.hamcrest.MatcherAssert.assertThat;
37+
import static org.hamcrest.core.IsNull.notNullValue;
38+
3639
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
3740
public class FullTest implements TestChecker {
3841

@@ -252,7 +255,12 @@ public void test300staticFile() throws IOException {
252255
checkResponse(target.path(badUrl).request().get(), 404).close();
253256
final String goodUrl = "/css/test.css";
254257
checkContentType(checkResponse(target.path(goodUrl).request().head(), 200), MIME_TEXT_CSS).close();
255-
checkContains(checkEntity(checkResponse(target.path(goodUrl).request().get(), 200), MIME_TEXT_CSS), ".qwazr {");
258+
try (final Response response = target.path(goodUrl).request().get()) {
259+
checkResponse(response, 200);
260+
checkContains(checkEntity(response, MIME_TEXT_CSS), ".qwazr {");
261+
assertThat(response.getHeaderString("Etag"), notNullValue());
262+
assertThat(response.getHeaderString("Last-Modified"), notNullValue());
263+
}
256264
}
257265

258266
@Test

src/test/java/com/qwazr/webapps/test/ServletTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import java.io.IOException;
3737
import java.nio.file.Files;
3838

39+
import static org.hamcrest.MatcherAssert.assertThat;
40+
import static org.hamcrest.core.Is.is;
41+
3942
public class ServletTest implements TestChecker {
4043

4144
public static WebappServer server;
@@ -95,6 +98,7 @@ public void testWebjars() throws IOException {
9598
target.path("webjars/bootstrap/4.3.1/css/bootstrap.css").request().get(), 200)) {
9699
final String content = checkEntity(response, MediaType.valueOf("text/css"));
97100
checkContains(content, "bootstrap");
101+
assertThat(response.getHeaderString("ETag"), is("bootstrap.css_4.3.1"));
98102
}
99103
}
100104

src/test/java/com/qwazr/webapps/test/TestServer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
*/
1616
package com.qwazr.webapps.test;
1717

18-
import com.google.common.io.Files;
1918
import com.qwazr.webapps.WebappServer;
2019
import org.apache.commons.io.FileUtils;
2120

2221
import java.io.File;
22+
import java.nio.file.Files;
2323
import java.nio.file.Paths;
2424

2525
public class TestServer {
@@ -29,7 +29,7 @@ public class TestServer {
2929
public static synchronized void startServer() throws Exception {
3030
if (WebappServer.getInstance() != null)
3131
return;
32-
final File dataDir = Files.createTempDir();
32+
final File dataDir = Files.createTempDirectory("webapp-date").toFile();
3333
System.setProperty("QWAZR_DATA", dataDir.getAbsolutePath());
3434
System.setProperty("PUBLIC_ADDR", "localhost");
3535
System.setProperty("LISTEN_ADDR", "localhost");

0 commit comments

Comments
 (0)