diff --git a/coverage-report/src/test/java/org/jooby/issues/Issue356.java b/coverage-report/src/test/java/org/jooby/issues/Issue356.java index 068ddc71f9..1182992212 100644 --- a/coverage-report/src/test/java/org/jooby/issues/Issue356.java +++ b/coverage-report/src/test/java/org/jooby/issues/Issue356.java @@ -23,7 +23,7 @@ public class Issue356 extends ServerFeature { .etag(true).lastModified(false).maxAge(Duration.ofDays(2))); assets("/assets/empty.css", new AssetHandler("/") - .etag(true).lastModified(true).maxAge(Duration.ofDays(7))); + .etag(true).lastModified(true).maxAge("7d")); } @Test diff --git a/jooby-assets/src/main/java/org/jooby/assets/Assets.java b/jooby-assets/src/main/java/org/jooby/assets/Assets.java index 02cd7f6240..996f2206b5 100644 --- a/jooby-assets/src/main/java/org/jooby/assets/Assets.java +++ b/jooby-assets/src/main/java/org/jooby/assets/Assets.java @@ -18,9 +18,6 @@ */ package org.jooby.assets; -import java.time.Duration; -import java.util.concurrent.TimeUnit; - import org.jooby.Env; import org.jooby.Jooby; import org.jooby.Router; @@ -333,10 +330,7 @@ public void configure(final Env env, final Config config, final Binder binder) { .cdn(conf.getString("assets.cdn")) .lastModified(conf.getBoolean("assets.lastModified")); - if (conf.hasPath("assets.cache.maxAge")) { - handler.maxAge(Duration - .ofSeconds(conf.getDuration("assets.cache.maxAge", TimeUnit.SECONDS))); - } + handler.maxAge(conf.getString("assets.cache.maxAge")); compiler.patterns().forEach(pattern -> routes.get(pattern, handler)); diff --git a/jooby-assets/src/test/java/org/jooby/assets/AssetsTest.java b/jooby-assets/src/test/java/org/jooby/assets/AssetsTest.java index c6363e6894..602e656d46 100644 --- a/jooby-assets/src/test/java/org/jooby/assets/AssetsTest.java +++ b/jooby-assets/src/test/java/org/jooby/assets/AssetsTest.java @@ -41,7 +41,8 @@ public class AssetsTest { public void configure() throws Exception { Config conf = ConfigFactory.empty() .withValue("application.path", ConfigValueFactory.fromAnyRef("/path")) - .withValue("assets.watch", ConfigValueFactory.fromAnyRef(false)); + .withValue("assets.watch", ConfigValueFactory.fromAnyRef(false)) + .withValue("assets.cache.maxAge", ConfigValueFactory.fromAnyRef(-1)); new MockUnit(Env.class, Binder.class, Request.class, Response.class, Route.Chain.class).expect(unit -> { AssetCompiler compiler = unit.constructor(AssetCompiler.class) @@ -95,7 +96,8 @@ public void configure() throws Exception { public void configureWithWatch() throws Exception { Config conf = ConfigFactory.empty() .withValue("application.path", ConfigValueFactory.fromAnyRef("/")) - .withValue("assets.watch", ConfigValueFactory.fromAnyRef(true)); + .withValue("assets.watch", ConfigValueFactory.fromAnyRef(true)) + .withValue("assets.cache.maxAge", ConfigValueFactory.fromAnyRef(-1)); new MockUnit(Env.class, Binder.class, Request.class, Response.class, Route.Chain.class).expect(unit -> { AssetCompiler compiler = unit.constructor(AssetCompiler.class) @@ -161,7 +163,8 @@ public void configureWithWatch() throws Exception { public void configureWithoutWatch() throws Exception { Config conf = ConfigFactory.empty() .withValue("application.path", ConfigValueFactory.fromAnyRef("/")) - .withValue("assets.watch", ConfigValueFactory.fromAnyRef(false)); + .withValue("assets.watch", ConfigValueFactory.fromAnyRef(false)) + .withValue("assets.cache.maxAge", ConfigValueFactory.fromAnyRef(-1)); new MockUnit(Env.class, Binder.class, Request.class, Response.class, Route.Chain.class).expect(unit -> { AssetCompiler compiler = unit.constructor(AssetCompiler.class) diff --git a/jooby/src/main/java/org/jooby/Jooby.java b/jooby/src/main/java/org/jooby/Jooby.java index 77778bb582..2efd5af860 100644 --- a/jooby/src/main/java/org/jooby/Jooby.java +++ b/jooby/src/main/java/org/jooby/Jooby.java @@ -1712,7 +1712,8 @@ public Route.Definition assets(final String path, final String location) { handler .cdn(conf.getString("assets.cdn")) .lastModified(conf.getBoolean("assets.lastModified")) - .etag(conf.getBoolean("assets.etag")); + .etag(conf.getBoolean("assets.etag")) + .maxAge(conf.getString("assets.cache.maxAge")); }); return assets(path, handler); } diff --git a/jooby/src/main/java/org/jooby/handlers/AssetHandler.java b/jooby/src/main/java/org/jooby/handlers/AssetHandler.java index 7a2e0885b7..37bf5e3881 100644 --- a/jooby/src/main/java/org/jooby/handlers/AssetHandler.java +++ b/jooby/src/main/java/org/jooby/handlers/AssetHandler.java @@ -28,7 +28,6 @@ import java.time.Duration; import java.util.Date; import java.util.Map; -import java.util.Optional; import org.jooby.Asset; import org.jooby.Jooby; @@ -40,9 +39,12 @@ import org.jooby.internal.URLAsset; import com.google.common.base.Strings; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigValueFactory; import javaslang.Function1; import javaslang.Function2; +import javaslang.control.Try; /** * Serve static resources, via {@link Jooby#assets(String)} or variants. @@ -94,7 +96,7 @@ public class AssetHandler implements Route.Handler { private boolean etag = true; - private Optional maxAge = Optional.empty(); + private long maxAge = -1; private boolean lastModified = true; @@ -191,8 +193,7 @@ public AssetHandler cdn(final String cdn) { * @return This handler. */ public AssetHandler maxAge(final Duration maxAge) { - this.maxAge = Optional.of(maxAge); - return this; + return maxAge(maxAge.getSeconds()); } /** @@ -200,7 +201,25 @@ public AssetHandler maxAge(final Duration maxAge) { * @return This handler. */ public AssetHandler maxAge(final long maxAge) { - return maxAge(Duration.ofSeconds(maxAge)); + this.maxAge = maxAge; + return this; + } + + /** + * Parse value as {@link Duration}. If the value is already a number then it uses as seconds. + * Otherwise, it parse expressions like: 8m, 1h, 365d, etc... + * + * @param maxAge Set the cache header max-age value in seconds. + * @return This handler. + */ + public AssetHandler maxAge(final String maxAge) { + Try.of(() -> Long.parseLong(maxAge)) + .recover(x -> ConfigFactory.empty() + .withValue("v", ConfigValueFactory.fromAnyRef(maxAge)) + .getDuration("v") + .getSeconds()) + .onSuccess(this::maxAge); + return this; } @Override @@ -263,9 +282,9 @@ private void doHandle(final Request req, final Response rsp, final Asset asset) } // cache max-age - maxAge.ifPresent(d -> { - rsp.header("Cache-Control", "max-age=" + d.getSeconds()); - }); + if (maxAge > 0) { + rsp.header("Cache-Control", "max-age=" + maxAge); + } send(req, rsp, asset); } diff --git a/jooby/src/test/java/org/jooby/JoobyTest.java b/jooby/src/test/java/org/jooby/JoobyTest.java index fed9799dcf..17f0bfc58b 100644 --- a/jooby/src/test/java/org/jooby/JoobyTest.java +++ b/jooby/src/test/java/org/jooby/JoobyTest.java @@ -2091,6 +2091,7 @@ public void assets() throws Exception { expect(conf.getString("assets.cdn")).andReturn("").times(2); expect(conf.getBoolean("assets.lastModified")).andReturn(true).times(2); expect(conf.getBoolean("assets.etag")).andReturn(true).times(2); + expect(conf.getString("assets.cache.maxAge")).andReturn("-1").times(2); Injector injector = unit.get(Injector.class); expect(injector.getInstance(Key.get(Config.class))).andReturn(conf).times(2);