diff --git a/framework-docs/modules/ROOT/pages/web/webflux/config.adoc b/framework-docs/modules/ROOT/pages/web/webflux/config.adoc index 9c255395a730..800e5f735010 100644 --- a/framework-docs/modules/ROOT/pages/web/webflux/config.adoc +++ b/framework-docs/modules/ROOT/pages/web/webflux/config.adoc @@ -620,7 +620,7 @@ resource URLs, since there are no view technologies that can make use of a non-b of resolvers and transformers. When serving only local resources, the workaround is to use `ResourceUrlProvider` directly (for example, through a custom element) and block. -Note that, when using both `EncodedResourceResolver` (for example, Gzip, Brotli encoded) and +Note that, when using both `EncodedResourceResolver` (for example, Gzip, Brotli, Zstd encoded) and `VersionedResourceResolver`, they must be registered in that order, to ensure content-based versions are always computed reliably based on the unencoded file. diff --git a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-config/static-resources.adoc b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-config/static-resources.adoc index f99633545081..faa32b0b197d 100644 --- a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-config/static-resources.adoc +++ b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-config/static-resources.adoc @@ -40,8 +40,8 @@ bean so that it can be injected into others. You can also make the rewrite trans `ResourceUrlEncodingFilter` for Thymeleaf, JSPs, FreeMarker, and others with URL tags that rely on `HttpServletResponse#encodeURL`. -Note that, when using both `EncodedResourceResolver` (for example, for serving gzipped or -brotli-encoded resources) and `VersionResourceResolver`, you must register them in this order. +Note that, when using both `EncodedResourceResolver` (for example, for serving gzipped, brotli, +or zstd encoded resources) and `VersionResourceResolver`, you must register them in this order. That ensures content-based versions are always computed reliably, based on the unencoded file. For https://www.webjars.org/documentation[WebJars], versioned URLs like diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/CachingResourceResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/CachingResourceResolver.java index b7d205bc55c5..fb75e64e1cc9 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/CachingResourceResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/CachingResourceResolver.java @@ -83,7 +83,7 @@ public Cache getCache() { * {@literal "Accept-Encoding"} header for which to cache resource variations. *
The codings configured here are generally expected to match those * configured on {@link EncodedResourceResolver#setContentCodings(List)}. - *
By default this property is set to {@literal ["br", "gzip"]} based on + *
By default this property is set to {@literal ["zstd", "br", "gzip"]} based on * the value of {@link EncodedResourceResolver#DEFAULT_CODINGS}. * @param codings one or more supported content codings * @since 5.1 diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/EncodedResourceResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/EncodedResourceResolver.java index 000af7a8e8e9..c10110082068 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/EncodedResourceResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/EncodedResourceResolver.java @@ -44,8 +44,8 @@ /** * Resolver that delegates to the chain, and if a resource is found, it then - * attempts to find an encoded (for example, gzip, brotli) variant that is acceptable - * based on the "Accept-Encoding" request header. + * attempts to find an encoded (for example, gzip, brotli, zstd) variant that is + * acceptable based on the "Accept-Encoding" request header. * *
The list of supported {@link #setContentCodings(List) contentCodings} can
* be configured, in order of preference, and each coding must be associated
@@ -56,6 +56,7 @@
* ensure the version calculation is not impacted by the encoding.
*
* @author Rossen Stoyanchev
+ * @author Toshiaki Maki
* @since 5.1
*/
public class EncodedResourceResolver extends AbstractResourceResolver {
@@ -63,7 +64,7 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
/**
* The default content codings.
*/
- public static final List By default this property is set to {@literal ["br", "gzip"]}.
+ * By default this property is set to {@literal ["zstd", "br", "gzip"]}.
* @param codings one or more supported content codings
*/
public void setContentCodings(List By default this is configured with {@literal ["br" -> ".br"]} and
- * {@literal ["gzip" -> ".gz"]}.
+ * By default this is configured with {@literal ["zstd" -> ".zst"]},
+ * {@literal ["br" -> ".br"]} and {@literal ["gzip" -> ".gz"]}.
* @param extensions the extensions to use.
* @see #registerExtension(String, String)
*/
diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/resource/EncodedResourceResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/resource/EncodedResourceResolverTests.java
index 6b4568ca2f01..802e75f2fced 100644
--- a/spring-webflux/src/test/java/org/springframework/web/reactive/resource/EncodedResourceResolverTests.java
+++ b/spring-webflux/src/test/java/org/springframework/web/reactive/resource/EncodedResourceResolverTests.java
@@ -40,6 +40,7 @@
* Tests for {@link EncodedResourceResolver}.
*
* @author Rossen Stoyanchev
+ * @author Toshiaki Maki
*/
@ExtendWith(GzipSupport.class)
class EncodedResourceResolverTests {
@@ -91,6 +92,24 @@ void resolveGzipped(GzippedFiles gzippedFiles) {
assertThat(headers.getFirst(HttpHeaders.VARY)).isEqualTo("Accept-Encoding");
}
+ @Test
+ void resolveZstd() {
+
+ MockServerWebExchange exchange = MockServerWebExchange.from(
+ MockServerHttpRequest.get("").header("Accept-Encoding", "zstd"));
+
+ String file = "js/foo.js";
+ Resource actual = this.resolver.resolveResource(exchange, file, this.locations).block(TIMEOUT);
+
+ assertThat(actual.getDescription()).isEqualTo(getResource(file + ".zst").getDescription());
+ assertThat(actual.getFilename()).isEqualTo(getResource(file).getFilename());
+
+ assertThat(actual).isInstanceOf(HttpResource.class);
+ HttpHeaders headers = ((HttpResource) actual).getResponseHeaders();
+ assertThat(headers.getFirst(HttpHeaders.CONTENT_ENCODING)).isEqualTo("zstd");
+ assertThat(headers.getFirst(HttpHeaders.VARY)).isEqualTo("Accept-Encoding");
+ }
+
@Test
void resolveGzippedWithVersion(GzippedFiles gzippedFiles) {
diff --git a/spring-webflux/src/test/resources/org/springframework/web/reactive/resource/test/js/foo.js.zst b/spring-webflux/src/test/resources/org/springframework/web/reactive/resource/test/js/foo.js.zst
new file mode 100644
index 000000000000..3edbf1399f7b
Binary files /dev/null and b/spring-webflux/src/test/resources/org/springframework/web/reactive/resource/test/js/foo.js.zst differ
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/CachingResourceResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/CachingResourceResolver.java
index f8575376d763..92825837d3a9 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/CachingResourceResolver.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/CachingResourceResolver.java
@@ -83,7 +83,7 @@ public Cache getCache() {
* {@literal "Accept-Encoding"} header for which to cache resource variations.
* The codings configured here are generally expected to match those
* configured on {@link EncodedResourceResolver#setContentCodings(List)}.
- * By default this property is set to {@literal ["br", "gzip"]} based on
+ * By default this property is set to {@literal ["zstd", "br", "gzip"]} based on
* the value of {@link EncodedResourceResolver#DEFAULT_CODINGS}.
* @param codings one or more supported content codings
* @since 5.1
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/EncodedResourceResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/EncodedResourceResolver.java
index b42abc226c1b..e75255ee85fe 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/EncodedResourceResolver.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/EncodedResourceResolver.java
@@ -43,8 +43,8 @@
/**
* Resolver that delegates to the chain, and if a resource is found, it then
- * attempts to find an encoded (for example, gzip, brotli) variant that is acceptable
- * based on the "Accept-Encoding" request header.
+ * attempts to find an encoded (for example, gzip, brotli, zstd) variant that is
+ * acceptable based on the "Accept-Encoding" request header.
*
* The list of supported {@link #setContentCodings(List) contentCodings} can
* be configured, in order of preference, and each coding must be associated
@@ -55,6 +55,7 @@
* ensure the version calculation is not impacted by the encoding.
*
* @author Rossen Stoyanchev
+ * @author Toshiaki Maki
* @since 5.1
*/
public class EncodedResourceResolver extends AbstractResourceResolver {
@@ -62,7 +63,7 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
/**
* The default content codings.
*/
- public static final List By default this property is set to {@literal ["br", "gzip"]}.
+ * By default this property is set to {@literal ["zstd", "br", "gzip"]}.
* @param codings one or more supported content codings
*/
public void setContentCodings(List By default this is configured with {@literal ["br" -> ".br"]} and
- * {@literal ["gzip" -> ".gz"]}.
+ * By default this is configured with {@literal ["zstd" -> ".zst"]},
+ * {@literal ["br" -> ".br"]} and {@literal ["gzip" -> ".gz"]}.
* @param extensions the extensions to use.
* @see #registerExtension(String, String)
*/
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/EncodedResourceResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/EncodedResourceResolverTests.java
index 4dabb47993a6..9b2ba56d341b 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/EncodedResourceResolverTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/EncodedResourceResolverTests.java
@@ -39,6 +39,7 @@
*
* @author Jeremy Grelle
* @author Rossen Stoyanchev
+ * @author Toshiaki Maki
*/
@ExtendWith(GzipSupport.class)
class EncodedResourceResolverTests {
@@ -84,6 +85,22 @@ void resolveGzipped(GzippedFiles gzippedFiles) {
assertThat(headers.getFirst(HttpHeaders.VARY)).isEqualTo("Accept-Encoding");
}
+ @Test
+ void resolveZstd() {
+ String file = "js/foo.js";
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addHeader("Accept-Encoding", "zstd");
+ Resource actual = this.resolver.resolveResource(request, file, this.locations);
+
+ assertThat(actual.getDescription()).isEqualTo(getResource(file + ".zst").getDescription());
+ assertThat(actual.getFilename()).isEqualTo(getResource(file).getFilename());
+
+ assertThat(actual).isInstanceOf(HttpResource.class);
+ HttpHeaders headers = ((HttpResource) actual).getResponseHeaders();
+ assertThat(headers.getFirst(HttpHeaders.CONTENT_ENCODING)).isEqualTo("zstd");
+ assertThat(headers.getFirst(HttpHeaders.VARY)).isEqualTo("Accept-Encoding");
+ }
+
@Test
void resolveGzippedWithVersion(GzippedFiles gzippedFiles) {
gzippedFiles.create("foo.css");
diff --git a/spring-webmvc/src/test/resources/org/springframework/web/servlet/resource/test/js/foo.js.zst b/spring-webmvc/src/test/resources/org/springframework/web/servlet/resource/test/js/foo.js.zst
new file mode 100644
index 000000000000..3edbf1399f7b
Binary files /dev/null and b/spring-webmvc/src/test/resources/org/springframework/web/servlet/resource/test/js/foo.js.zst differ