Add caching headers to If-Unmodified-Since responses

Conditional requests using "If-Unmodified-Since" headers are generally
used as precondition checks for state-changing methods (POST, PUT,
DELETE). See https://datatracker.ietf.org/doc/html/rfc7232#section-3.4
The spec also allows for idempotent methods like GET and HEAD.

Prior to this commit, the "If-Unmodified-Since" processing done in
`checkNotModified` (see `ServletWebRequest` and
`DefaultServerWebExchange`) would only focus on the state changing
methods and not take into account the safe methods. For those cases, the
"ETag" and "Last-Modified" would be missing from the response.

This commit ensures that such headers are added as expected in these
cases.

Fixes gh-29362
This commit is contained in:
Brian Clozel
2022-10-21 15:11:08 +02:00
parent 12cc8a9f07
commit 9410998897
4 changed files with 52 additions and 15 deletions

View File

@@ -220,6 +220,12 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
if (this.notModified && response != null) {
response.setStatus(HttpStatus.PRECONDITION_FAILED.value());
}
if (SAFE_METHODS.contains(getRequest().getMethod())) {
if (StringUtils.hasLength(etag) && response.getHeader(HttpHeaders.ETAG) == null) {
response.setHeader(HttpHeaders.ETAG, padEtagIfNecessary(etag));
}
response.setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedTimestamp);
}
return this.notModified;
}

View File

@@ -56,6 +56,7 @@ import org.springframework.web.server.session.WebSessionManager;
* Default implementation of {@link ServerWebExchange}.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 5.0
*/
public class DefaultServerWebExchange implements ServerWebExchange {
@@ -261,6 +262,12 @@ public class DefaultServerWebExchange implements ServerWebExchange {
if (this.notModified) {
getResponse().setStatusCode(HttpStatus.PRECONDITION_FAILED);
}
if (SAFE_METHODS.contains(getRequest().getMethod())) {
if (StringUtils.hasLength(etag) && getResponseHeaders().getETag() == null) {
getResponseHeaders().setETag(padEtagIfNecessary(etag));
}
getResponseHeaders().setLastModified(lastModified.toEpochMilli());
}
return this.notModified;
}