diff --git a/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java index 64690c9495f7..6251f57c25af 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java @@ -202,7 +202,7 @@ public boolean checkNotModified(String etag) { @Override public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestamp) { - if (this.notModified) { + if (isNotModified()) { return true; } @@ -213,6 +213,8 @@ public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestam // Evaluate conditions in order of precedence. // See https://datatracker.ietf.org/doc/html/rfc9110#section-13.2.2 + + // 1) If-Match if (validateIfMatch(etag)) { updateResponseStateChanging(etag, lastModifiedTimestamp); return this.notModified; diff --git a/spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java b/spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java index 3564cc8629ca..eb22f4ad3860 100644 --- a/spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java +++ b/spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java @@ -117,7 +117,7 @@ private void updateResponse(HttpServletRequest request, HttpServletResponse resp Assert.notNull(wrapper, "ContentCachingResponseWrapper not found"); HttpServletResponse rawResponse = (HttpServletResponse) wrapper.getResponse(); - if (isEligibleForEtag(request, wrapper, wrapper.getStatus(), wrapper.getContentInputStream())) { + if (isEligibleForEtag(request, wrapper)) { String eTag = wrapper.getHeader(HttpHeaders.ETAG); if (!StringUtils.hasText(eTag)) { eTag = generateETagHeaderValue(wrapper.getContentInputStream(), this.writeWeakETag); @@ -142,12 +142,10 @@ private void updateResponse(HttpServletRequest request, HttpServletResponse resp * * @param request the HTTP request * @param response the HTTP response - * @param responseStatusCode the HTTP response status code - * @param inputStream the response body * @return {@code true} if eligible for ETag generation, {@code false} otherwise */ - protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, - int responseStatusCode, InputStream inputStream) { + protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response) { + int responseStatusCode = response.getStatus(); if (!response.isCommitted() && responseStatusCode >= 200 && responseStatusCode < 300 && diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java b/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java index 0500180897b1..3cdee63bd38d 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java @@ -300,19 +300,25 @@ public boolean checkNotModified(String etag) { @Override public boolean checkNotModified(@Nullable String eTag, Instant lastModified) { + if (isNotModified()) { + return true; + } + HttpStatusCode status = getResponse().getStatusCode(); - if (this.notModified || (status != null && !HttpStatus.OK.equals(status))) { - return this.notModified; + if (status != null && !HttpStatus.OK.equals(status)) { + return false; } + // Evaluate conditions in order of precedence. // See https://datatracker.ietf.org/doc/html/rfc9110#section-13.2.2 + // 1) If-Match if (validateIfMatch(eTag)) { updateResponseStateChanging(eTag, lastModified); return this.notModified; } // 2) If-Unmodified-Since - else if (validateIfUnmodifiedSince(lastModified)) { + if (validateIfUnmodifiedSince(lastModified)) { updateResponseStateChanging(eTag, lastModified); return this.notModified; } diff --git a/spring-web/src/test/java/org/springframework/web/filter/ShallowEtagHeaderFilterTests.java b/spring-web/src/test/java/org/springframework/web/filter/ShallowEtagHeaderFilterTests.java index 576d28d0d4ca..aa4b9e4199b7 100644 --- a/spring-web/src/test/java/org/springframework/web/filter/ShallowEtagHeaderFilterTests.java +++ b/spring-web/src/test/java/org/springframework/web/filter/ShallowEtagHeaderFilterTests.java @@ -16,8 +16,6 @@ package org.springframework.web.filter; -import java.io.InputStream; - import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletResponse; import org.junit.jupiter.api.Test; @@ -49,18 +47,17 @@ void isEligibleForEtag() { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels"); MockHttpServletResponse response = new MockHttpServletResponse(); - assertThat(filter.isEligibleForEtag(request, response, 200, InputStream.nullInputStream())).isTrue(); - assertThat(filter.isEligibleForEtag(request, response, 300, InputStream.nullInputStream())).isFalse(); + assertThat(filter.isEligibleForEtag(request, response)).isTrue(); request = new MockHttpServletRequest("HEAD", "/hotels"); - assertThat(filter.isEligibleForEtag(request, response, 200, InputStream.nullInputStream())).isFalse(); + assertThat(filter.isEligibleForEtag(request, response)).isFalse(); request = new MockHttpServletRequest("POST", "/hotels"); - assertThat(filter.isEligibleForEtag(request, response, 200, InputStream.nullInputStream())).isFalse(); + assertThat(filter.isEligibleForEtag(request, response)).isFalse(); request = new MockHttpServletRequest("POST", "/hotels"); request.addHeader("Cache-Control","must-revalidate, no-store"); - assertThat(filter.isEligibleForEtag(request, response, 200, InputStream.nullInputStream())).isFalse(); + assertThat(filter.isEligibleForEtag(request, response)).isFalse(); } @Test @@ -172,7 +169,7 @@ void filterWriter() throws Exception { } @Test // SPR-12960 - public void filterWriterWithDisabledCaching() throws Exception { + void filterWriterWithDisabledCaching() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels"); MockHttpServletResponse response = new MockHttpServletResponse(); response.setContentType(TEXT_PLAIN_VALUE); @@ -257,7 +254,7 @@ void filterSendRedirect() throws Exception { } @Test // SPR-13717 - public void filterFlushResponse() throws Exception { + void filterFlushResponse() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels"); MockHttpServletResponse response = new MockHttpServletResponse();