From 3dd4a8350afbec5728feb7232278400cbf24b8a7 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 9 Sep 2024 18:39:20 +0100 Subject: [PATCH] Update more places to use quoteETagIfNecessary Closes gh-33412 --- .../org/springframework/http/HttpHeaders.java | 10 +++---- .../context/request/ServletWebRequest.java | 29 +++++++------------ .../adapter/DefaultServerWebExchange.java | 20 ++++--------- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java index e262ee85f45..7ce36aad2ee 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java @@ -1063,11 +1063,11 @@ public class HttpHeaders implements MultiValueMap, Serializable /** * Set the (new) entity tag of the body, as specified by the {@code ETag} header. */ - public void setETag(@Nullable String etag) { - if (etag != null) { - Assert.isTrue(etag.startsWith("\"") || etag.startsWith("W/\""), "ETag does not start with W/\" or \""); - Assert.isTrue(etag.endsWith("\""), "ETag does not end with \""); - set(ETAG, etag); + public void setETag(@Nullable String eTag) { + if (eTag != null) { + Assert.isTrue(eTag.startsWith("\"") || eTag.startsWith("W/\""), "ETag does not start with W/\" or \""); + Assert.isTrue(eTag.endsWith("\""), "ETag does not end with \""); + set(ETAG, eTag); } else { remove(ETAG); 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 cac176df2b7..141a258c149 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 @@ -247,23 +247,25 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ return true; } - private boolean matchRequestedETags(Enumeration requestedETags, @Nullable String etag, boolean weakCompare) { - etag = padEtagIfNecessary(etag); + private boolean matchRequestedETags(Enumeration requestedETags, @Nullable String eTag, boolean weakCompare) { + if (StringUtils.hasLength(eTag)) { + eTag = ETag.quoteETagIfNecessary(eTag); + } while (requestedETags.hasMoreElements()) { // Compare weak/strong ETags as per https://datatracker.ietf.org/doc/html/rfc9110#section-8.8.3 for (ETag requestedETag : ETag.parse(requestedETags.nextElement())) { // only consider "lost updates" checks for unsafe HTTP methods - if (requestedETag.isWildcard() && StringUtils.hasLength(etag) + if (requestedETag.isWildcard() && StringUtils.hasLength(eTag) && !SAFE_METHODS.contains(getRequest().getMethod())) { return false; } if (weakCompare) { - if (etagWeakMatch(etag, requestedETag.formattedTag())) { + if (etagWeakMatch(eTag, requestedETag.formattedTag())) { return false; } } else { - if (etagStrongMatch(etag, requestedETag.formattedTag())) { + if (etagStrongMatch(eTag, requestedETag.formattedTag())) { return false; } } @@ -272,17 +274,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ return true; } - @Nullable - private String padEtagIfNecessary(@Nullable String etag) { - if (!StringUtils.hasLength(etag)) { - return etag; - } - if ((etag.startsWith("\"") || etag.startsWith("W/\"")) && etag.endsWith("\"")) { - return etag; - } - return "\"" + etag + "\""; - } - private boolean etagStrongMatch(@Nullable String first, @Nullable String second) { if (!StringUtils.hasLength(first) || first.startsWith("W/")) { return false; @@ -346,13 +337,13 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ } } - private void addCachingResponseHeaders(@Nullable String etag, long lastModifiedTimestamp) { + private void addCachingResponseHeaders(@Nullable String eTag, long lastModifiedTimestamp) { if (getResponse() != null && SAFE_METHODS.contains(getRequest().getMethod())) { if (lastModifiedTimestamp > 0 && parseDateValue(getResponse().getHeader(HttpHeaders.LAST_MODIFIED)) == -1) { getResponse().setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedTimestamp); } - if (StringUtils.hasLength(etag) && getResponse().getHeader(HttpHeaders.ETAG) == null) { - getResponse().setHeader(HttpHeaders.ETAG, padEtagIfNecessary(etag)); + if (StringUtils.hasLength(eTag) && getResponse().getHeader(HttpHeaders.ETAG) == null) { + getResponse().setHeader(HttpHeaders.ETAG, ETag.quoteETagIfNecessary(eTag)); } } } 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 c17beb484b8..09c833ce479 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.i18n.LocaleContext; import org.springframework.core.ResolvableType; import org.springframework.core.codec.Hints; +import org.springframework.http.ETag; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -341,7 +342,9 @@ public class DefaultServerWebExchange implements ServerWebExchange { } private boolean matchRequestedETags(List requestedETags, @Nullable String eTag, boolean weakCompare) { - eTag = padEtagIfNecessary(eTag); + if (StringUtils.hasLength(eTag)) { + eTag = ETag.quoteETagIfNecessary(eTag); + } for (String clientEtag : requestedETags) { // only consider "lost updates" checks for unsafe HTTP methods if ("*".equals(clientEtag) && StringUtils.hasLength(eTag) @@ -363,17 +366,6 @@ public class DefaultServerWebExchange implements ServerWebExchange { return true; } - @Nullable - private String padEtagIfNecessary(@Nullable String etag) { - if (!StringUtils.hasLength(etag)) { - return etag; - } - if ((etag.startsWith("\"") || etag.startsWith("W/\"")) && etag.endsWith("\"")) { - return etag; - } - return "\"" + etag + "\""; - } - private boolean eTagStrongMatch(@Nullable String first, @Nullable String second) { if (!StringUtils.hasLength(first) || first.startsWith("W/")) { return false; @@ -431,7 +423,7 @@ public class DefaultServerWebExchange implements ServerWebExchange { getResponseHeaders().setLastModified(lastModified.toEpochMilli()); } if (StringUtils.hasLength(eTag) && getResponseHeaders().getETag() == null) { - getResponseHeaders().setETag(padEtagIfNecessary(eTag)); + getResponseHeaders().setETag(ETag.quoteETagIfNecessary(eTag)); } } }