Merge branch '7.0.x'

This commit is contained in:
Brian Clozel
2026-03-20 15:56:10 +01:00
4 changed files with 58 additions and 45 deletions
@@ -17,10 +17,8 @@
package org.springframework.web.reactive.resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
@@ -133,15 +131,12 @@ public class CachingResourceResolver extends AbstractResourceResolver {
}
private @Nullable String getContentCodingKey(ServerWebExchange exchange) {
String header = exchange.getRequest().getHeaders().getFirst("Accept-Encoding");
if (!StringUtils.hasText(header)) {
List<String> acceptedCodings = EncodedResourceResolver.parseAcceptEncoding(exchange);
if (acceptedCodings.isEmpty()) {
return null;
}
return Arrays.stream(StringUtils.tokenizeToStringArray(header, ","))
.map(token -> {
int index = token.indexOf(';');
return (index >= 0 ? token.substring(0, index) : token).trim().toLowerCase(Locale.ROOT);
})
return acceptedCodings
.stream()
.filter(this.contentCodings::contains)
.sorted()
.collect(Collectors.joining(","));
@@ -38,8 +38,8 @@ import reactor.core.publisher.Mono;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
/**
@@ -142,23 +142,23 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
return resource;
}
String acceptEncoding = getAcceptEncoding(exchange);
if (acceptEncoding == null) {
List<String> acceptedCodings = parseAcceptEncoding(exchange);
if (acceptedCodings.isEmpty()) {
return resource;
}
for (String coding : this.contentCodings) {
if (acceptEncoding.contains(coding)) {
for (String acceptedCoding : acceptedCodings) {
if (this.contentCodings.contains(acceptedCoding)) {
try {
String extension = getExtension(coding);
Resource encoded = new EncodedResource(resource, coding, extension);
String extension = getExtension(acceptedCoding);
Resource encoded = new EncodedResource(resource, acceptedCoding, extension);
if (encoded.exists()) {
return encoded;
}
}
catch (IOException ex) {
logger.trace(exchange.getLogPrefix() +
"No " + coding + " resource for [" + resource.getFilename() + "]", ex);
"No " + acceptedCoding + " resource for [" + resource.getFilename() + "]", ex);
}
}
}
@@ -167,12 +167,6 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
});
}
private @Nullable String getAcceptEncoding(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest();
String header = request.getHeaders().getFirst(HttpHeaders.ACCEPT_ENCODING);
return (header != null ? header.toLowerCase(Locale.ROOT) : null);
}
private String getExtension(String coding) {
String extension = this.extensions.get(coding);
if (extension == null) {
@@ -188,6 +182,23 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
return chain.resolveUrlPath(resourceUrlPath, locations);
}
/**
* Parse the accepted encodings from the given HTTP exchange request.
*/
static List<String> parseAcceptEncoding(ServerWebExchange exchange) {
String header = exchange.getRequest().getHeaders().getFirst("Accept-Encoding");
if (!StringUtils.hasText(header)) {
return Collections.emptyList();
}
header = header.toLowerCase(Locale.ROOT);
return Arrays.stream(StringUtils.tokenizeToStringArray(header, ","))
.map(token -> {
int index = token.indexOf(';');
return (index >= 0 ? token.substring(0, index) : token).trim();
})
.toList();
}
/**
* An encoded {@link HttpResource}.
@@ -17,10 +17,8 @@
package org.springframework.web.servlet.resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletRequest;
@@ -29,7 +27,6 @@ import org.jspecify.annotations.Nullable;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -139,15 +136,12 @@ public class CachingResourceResolver extends AbstractResourceResolver {
}
private @Nullable String getContentCodingKey(HttpServletRequest request) {
String header = request.getHeader(HttpHeaders.ACCEPT_ENCODING);
if (!StringUtils.hasText(header)) {
List<String> acceptedCodings = EncodedResourceResolver.parseAcceptEncoding(request);
if (acceptedCodings.isEmpty()) {
return null;
}
return Arrays.stream(StringUtils.tokenizeToStringArray(header, ","))
.map(token -> {
int index = token.indexOf(';');
return (index >= 0 ? token.substring(0, index) : token).trim().toLowerCase(Locale.ROOT);
})
return acceptedCodings
.stream()
.filter(this.contentCodings::contains)
.sorted()
.collect(Collectors.joining(","));
@@ -39,6 +39,7 @@ import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Resolver that delegates to the chain, and if a resource is found, it then
@@ -139,23 +140,23 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
return resource;
}
String acceptEncoding = getAcceptEncoding(request);
if (acceptEncoding == null) {
List<String> acceptedCodings = parseAcceptEncoding(request);
if (acceptedCodings.isEmpty()) {
return resource;
}
for (String coding : this.contentCodings) {
if (acceptEncoding.contains(coding)) {
for (String acceptedCoding : acceptedCodings) {
if (this.contentCodings.contains(acceptedCoding)) {
try {
String extension = getExtension(coding);
Resource encoded = new EncodedResource(resource, coding, extension);
String extension = getExtension(acceptedCoding);
Resource encoded = new EncodedResource(resource, acceptedCoding, extension);
if (encoded.exists()) {
return encoded;
}
}
catch (IOException ex) {
if (logger.isTraceEnabled()) {
logger.trace("No " + coding + " resource for [" + resource.getFilename() + "]", ex);
logger.trace("No " + acceptedCoding + " resource for [" + resource.getFilename() + "]", ex);
}
}
}
@@ -164,11 +165,6 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
return resource;
}
private @Nullable String getAcceptEncoding(HttpServletRequest request) {
String header = request.getHeader(HttpHeaders.ACCEPT_ENCODING);
return (header != null ? header.toLowerCase(Locale.ROOT) : null);
}
private String getExtension(String coding) {
String extension = this.extensions.get(coding);
if (extension == null) {
@@ -184,6 +180,23 @@ public class EncodedResourceResolver extends AbstractResourceResolver {
return chain.resolveUrlPath(resourceUrlPath, locations);
}
/**
* Parse the accepted encodings from the given HTTP request.
*/
static List<String> parseAcceptEncoding(HttpServletRequest request) {
String header = request.getHeader("Accept-Encoding");
if (!StringUtils.hasText(header)) {
return Collections.emptyList();
}
header = header.toLowerCase(Locale.ROOT);
return Arrays.stream(StringUtils.tokenizeToStringArray(header, ","))
.map(token -> {
int index = token.indexOf(';');
return (index >= 0 ? token.substring(0, index) : token).trim();
})
.toList();
}
/**
* An encoded {@link HttpResource}.