Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion framework-docs/modules/ROOT/pages/web/webflux/config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public Cache getCache() {
* {@literal "Accept-Encoding"} header for which to cache resource variations.
* <p>The codings configured here are generally expected to match those
* configured on {@link EncodedResourceResolver#setContentCodings(List)}.
* <p>By default this property is set to {@literal ["br", "gzip"]} based on
* <p>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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>The list of supported {@link #setContentCodings(List) contentCodings} can
* be configured, in order of preference, and each coding must be associated
Expand All @@ -56,14 +56,15 @@
* ensure the version calculation is not impacted by the encoding.
*
* @author Rossen Stoyanchev
* @author Toshiaki Maki
* @since 5.1
*/
public class EncodedResourceResolver extends AbstractResourceResolver {

/**
* The default content codings.
*/
public static final List<String> DEFAULT_CODINGS = Arrays.asList("br", "gzip");
public static final List<String> DEFAULT_CODINGS = Arrays.asList("zstd", "br", "gzip");


private final List<String> contentCodings = new ArrayList<>(DEFAULT_CODINGS);
Expand All @@ -74,6 +75,7 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
public EncodedResourceResolver() {
this.extensions.put("gzip", ".gz");
this.extensions.put("br", ".br");
this.extensions.put("zstd", ".zst");
}


Expand All @@ -87,7 +89,7 @@ public EncodedResourceResolver() {
* customizations to the list of codings here should be matched by
* customizations to the same list in {@link CachingResourceResolver} to
* ensure encoded variants of a resource are cached under separate keys.
* <p>By default this property is set to {@literal ["br", "gzip"]}.
* <p>By default this property is set to {@literal ["zstd", "br", "gzip"]}.
* @param codings one or more supported content codings
*/
public void setContentCodings(List<String> codings) {
Expand All @@ -106,8 +108,8 @@ public List<String> getContentCodings() {
/**
* Configure mappings from content codings to file extensions. A dot "."
* will be prepended in front of the extension value if not present.
* <p>By default this is configured with {@literal ["br" -> ".br"]} and
* {@literal ["gzip" -> ".gz"]}.
* <p>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)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
* Tests for {@link EncodedResourceResolver}.
*
* @author Rossen Stoyanchev
* @author Toshiaki Maki
*/
@ExtendWith(GzipSupport.class)
class EncodedResourceResolverTests {
Expand Down Expand Up @@ -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) {

Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public Cache getCache() {
* {@literal "Accept-Encoding"} header for which to cache resource variations.
* <p>The codings configured here are generally expected to match those
* configured on {@link EncodedResourceResolver#setContentCodings(List)}.
* <p>By default this property is set to {@literal ["br", "gzip"]} based on
* <p>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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>The list of supported {@link #setContentCodings(List) contentCodings} can
* be configured, in order of preference, and each coding must be associated
Expand All @@ -55,14 +55,15 @@
* ensure the version calculation is not impacted by the encoding.
*
* @author Rossen Stoyanchev
* @author Toshiaki Maki
* @since 5.1
*/
public class EncodedResourceResolver extends AbstractResourceResolver {

/**
* The default content codings.
*/
public static final List<String> DEFAULT_CODINGS = Arrays.asList("br", "gzip");
public static final List<String> DEFAULT_CODINGS = Arrays.asList("zstd", "br", "gzip");


private final List<String> contentCodings = new ArrayList<>(DEFAULT_CODINGS);
Expand All @@ -73,6 +74,7 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
public EncodedResourceResolver() {
this.extensions.put("gzip", ".gz");
this.extensions.put("br", ".br");
this.extensions.put("zstd", ".zst");
}


Expand All @@ -86,7 +88,7 @@ public EncodedResourceResolver() {
* customizations to the list of codings here should be matched by
* customizations to the same list in {@link CachingResourceResolver} to
* ensure encoded variants of a resource are cached under separate keys.
* <p>By default this property is set to {@literal ["br", "gzip"]}.
* <p>By default this property is set to {@literal ["zstd", "br", "gzip"]}.
* @param codings one or more supported content codings
*/
public void setContentCodings(List<String> codings) {
Expand All @@ -105,8 +107,8 @@ public List<String> getContentCodings() {
/**
* Configure mappings from content codings to file extensions. A dot "."
* will be prepended in front of the extension value if not present.
* <p>By default this is configured with {@literal ["br" -> ".br"]} and
* {@literal ["gzip" -> ".gz"]}.
* <p>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)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
*
* @author Jeremy Grelle
* @author Rossen Stoyanchev
* @author Toshiaki Maki
*/
@ExtendWith(GzipSupport.class)
class EncodedResourceResolverTests {
Expand Down Expand Up @@ -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");
Expand Down
Binary file not shown.