Quote ETag if not quoted in HttpHeaders#setETag
This aligns HttpHeaders with other places like ServletWebRequest and DefaultWebExchange where an ETag is accepted as input. It also allows us to remove quoting from places that delegate to HttpHeaders#setETag since it now does that internally. Closes gh-33412
This commit is contained in:
@@ -1063,11 +1063,9 @@ public class HttpHeaders implements MultiValueMap<String, String>, 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 tag) {
|
||||
if (tag != null) {
|
||||
set(ETAG, ETag.quoteETagIfNecessary(tag));
|
||||
}
|
||||
else {
|
||||
remove(ETAG);
|
||||
|
||||
@@ -568,9 +568,8 @@ public class ResponseEntity<T> extends HttpEntity<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BodyBuilder eTag(@Nullable String eTag) {
|
||||
eTag = (eTag != null ? ETag.quoteETagIfNecessary(eTag) : eTag);
|
||||
this.headers.setETag(eTag);
|
||||
public BodyBuilder eTag(@Nullable String tag) {
|
||||
this.headers.setETag(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -417,13 +417,13 @@ public class DefaultServerWebExchange implements ServerWebExchange {
|
||||
addCachingResponseHeaders(eTag, lastModified);
|
||||
}
|
||||
|
||||
private void addCachingResponseHeaders(@Nullable String eTag, Instant lastModified) {
|
||||
private void addCachingResponseHeaders(@Nullable String tag, Instant lastModified) {
|
||||
if (SAFE_METHODS.contains(getRequest().getMethod())) {
|
||||
if (lastModified.isAfter(Instant.EPOCH) && getResponseHeaders().getLastModified() == -1) {
|
||||
getResponseHeaders().setLastModified(lastModified.toEpochMilli());
|
||||
}
|
||||
if (StringUtils.hasLength(eTag) && getResponseHeaders().getETag() == null) {
|
||||
getResponseHeaders().setETag(ETag.quoteETagIfNecessary(eTag));
|
||||
if (StringUtils.hasLength(tag) && getResponseHeaders().getETag() == null) {
|
||||
getResponseHeaders().setETag(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,15 +214,15 @@ class HttpHeadersTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void illegalETagWithoutQuotes() {
|
||||
String eTag = "v2.6";
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> headers.setETag(eTag));
|
||||
void eTagWithoutQuotes() {
|
||||
headers.setETag("v2.6");
|
||||
assertThat(headers.getETag()).isEqualTo("\"v2.6\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void illegalWeakETagWithoutLeadingQuote() {
|
||||
String etag = "W/v2.6\"";
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> headers.setETag(etag));
|
||||
void weakETagWithoutLeadingQuote() {
|
||||
headers.setETag("W/v2.6\"");
|
||||
assertThat(headers.getETag()).isEqualTo("\"W/v2.6\"\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -148,9 +148,8 @@ class DefaultEntityResponseBuilder<T> implements EntityResponse.Builder<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityResponse.Builder<T> eTag(String eTag) {
|
||||
eTag = ETag.quoteETagIfNecessary(eTag);
|
||||
this.headers.setETag(eTag);
|
||||
public EntityResponse.Builder<T> eTag(String tag) {
|
||||
this.headers.setETag(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -147,10 +147,8 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerResponse.BodyBuilder eTag(String eTag) {
|
||||
Assert.notNull(eTag, "etag must not be null");
|
||||
eTag = ETag.quoteETagIfNecessary(eTag);
|
||||
this.headers.setETag(eTag);
|
||||
public ServerResponse.BodyBuilder eTag(String tag) {
|
||||
this.headers.setETag(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -332,8 +332,7 @@ public class VersionResourceResolver extends AbstractResourceResolver {
|
||||
|
||||
@Override
|
||||
public HttpHeaders getResponseHeaders() {
|
||||
HttpHeaders headers = (this.original instanceof HttpResource httpResource ?
|
||||
httpResource.getResponseHeaders() : new HttpHeaders());
|
||||
HttpHeaders headers = (this.original instanceof HttpResource hr ? hr.getResponseHeaders() : new HttpHeaders());
|
||||
headers.setETag("W/\"" + this.version + "\"");
|
||||
return headers;
|
||||
}
|
||||
|
||||
@@ -166,9 +166,8 @@ final class DefaultEntityResponseBuilder<T> implements EntityResponse.Builder<T>
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityResponse.Builder<T> eTag(String eTag) {
|
||||
eTag = ETag.quoteETagIfNecessary(eTag);
|
||||
this.headers.setETag(eTag);
|
||||
public EntityResponse.Builder<T> eTag(String tag) {
|
||||
this.headers.setETag(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,10 +127,8 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerResponse.BodyBuilder eTag(String eTag) {
|
||||
Assert.notNull(eTag, "etag must not be null");
|
||||
eTag = ETag.quoteETagIfNecessary(eTag);
|
||||
this.headers.setETag(eTag);
|
||||
public ServerResponse.BodyBuilder eTag(String tag) {
|
||||
this.headers.setETag(tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user