Skip to content

Commit 19700d0

Browse files
committed
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
1 parent 3dd4a83 commit 19700d0

File tree

9 files changed

+24
-34
lines changed

9 files changed

+24
-34
lines changed

spring-web/src/main/java/org/springframework/http/HttpHeaders.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,11 +1063,9 @@ public long getDate() {
10631063
/**
10641064
* Set the (new) entity tag of the body, as specified by the {@code ETag} header.
10651065
*/
1066-
public void setETag(@Nullable String eTag) {
1067-
if (eTag != null) {
1068-
Assert.isTrue(eTag.startsWith("\"") || eTag.startsWith("W/\""), "ETag does not start with W/\" or \"");
1069-
Assert.isTrue(eTag.endsWith("\""), "ETag does not end with \"");
1070-
set(ETAG, eTag);
1066+
public void setETag(@Nullable String tag) {
1067+
if (tag != null) {
1068+
set(ETAG, ETag.quoteETagIfNecessary(tag));
10711069
}
10721070
else {
10731071
remove(ETAG);

spring-web/src/main/java/org/springframework/http/ResponseEntity.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,9 +568,8 @@ public BodyBuilder contentType(MediaType contentType) {
568568
}
569569

570570
@Override
571-
public BodyBuilder eTag(@Nullable String eTag) {
572-
eTag = (eTag != null ? ETag.quoteETagIfNecessary(eTag) : eTag);
573-
this.headers.setETag(eTag);
571+
public BodyBuilder eTag(@Nullable String tag) {
572+
this.headers.setETag(tag);
574573
return this;
575574
}
576575

spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,13 +417,13 @@ private void updateResponseIdempotent(@Nullable String eTag, Instant lastModifie
417417
addCachingResponseHeaders(eTag, lastModified);
418418
}
419419

420-
private void addCachingResponseHeaders(@Nullable String eTag, Instant lastModified) {
420+
private void addCachingResponseHeaders(@Nullable String tag, Instant lastModified) {
421421
if (SAFE_METHODS.contains(getRequest().getMethod())) {
422422
if (lastModified.isAfter(Instant.EPOCH) && getResponseHeaders().getLastModified() == -1) {
423423
getResponseHeaders().setLastModified(lastModified.toEpochMilli());
424424
}
425-
if (StringUtils.hasLength(eTag) && getResponseHeaders().getETag() == null) {
426-
getResponseHeaders().setETag(ETag.quoteETagIfNecessary(eTag));
425+
if (StringUtils.hasLength(tag) && getResponseHeaders().getETag() == null) {
426+
getResponseHeaders().setETag(tag);
427427
}
428428
}
429429
}

spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ void ipv6Host() {
214214
}
215215

216216
@Test
217-
void illegalETagWithoutQuotes() {
218-
String eTag = "v2.6";
219-
assertThatIllegalArgumentException().isThrownBy(() -> headers.setETag(eTag));
217+
void eTagWithoutQuotes() {
218+
headers.setETag("v2.6");
219+
assertThat(headers.getETag()).isEqualTo("\"v2.6\"");
220220
}
221221

222222
@Test
223-
void illegalWeakETagWithoutLeadingQuote() {
224-
String etag = "W/v2.6\"";
225-
assertThatIllegalArgumentException().isThrownBy(() -> headers.setETag(etag));
223+
void weakETagWithoutLeadingQuote() {
224+
headers.setETag("W/v2.6\"");
225+
assertThat(headers.getETag()).isEqualTo("\"W/v2.6\"\"");
226226
}
227227

228228
@Test

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultEntityResponseBuilder.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,8 @@ public EntityResponse.Builder<T> contentType(MediaType contentType) {
148148
}
149149

150150
@Override
151-
public EntityResponse.Builder<T> eTag(String eTag) {
152-
eTag = ETag.quoteETagIfNecessary(eTag);
153-
this.headers.setETag(eTag);
151+
public EntityResponse.Builder<T> eTag(String tag) {
152+
this.headers.setETag(tag);
154153
return this;
155154
}
156155

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,8 @@ public ServerResponse.BodyBuilder contentType(MediaType contentType) {
147147
}
148148

149149
@Override
150-
public ServerResponse.BodyBuilder eTag(String eTag) {
151-
Assert.notNull(eTag, "etag must not be null");
152-
eTag = ETag.quoteETagIfNecessary(eTag);
153-
this.headers.setETag(eTag);
150+
public ServerResponse.BodyBuilder eTag(String tag) {
151+
this.headers.setETag(tag);
154152
return this;
155153
}
156154

spring-webflux/src/main/java/org/springframework/web/reactive/resource/VersionResourceResolver.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -332,8 +332,7 @@ public String getDescription() {
332332

333333
@Override
334334
public HttpHeaders getResponseHeaders() {
335-
HttpHeaders headers = (this.original instanceof HttpResource httpResource ?
336-
httpResource.getResponseHeaders() : new HttpHeaders());
335+
HttpHeaders headers = (this.original instanceof HttpResource hr ? hr.getResponseHeaders() : new HttpHeaders());
337336
headers.setETag("W/\"" + this.version + "\"");
338337
return headers;
339338
}

spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultEntityResponseBuilder.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,8 @@ public EntityResponse.Builder<T> contentType(MediaType contentType) {
166166
}
167167

168168
@Override
169-
public EntityResponse.Builder<T> eTag(String eTag) {
170-
eTag = ETag.quoteETagIfNecessary(eTag);
171-
this.headers.setETag(eTag);
169+
public EntityResponse.Builder<T> eTag(String tag) {
170+
this.headers.setETag(tag);
172171
return this;
173172
}
174173

spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerResponseBuilder.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,8 @@ public ServerResponse.BodyBuilder contentType(MediaType contentType) {
127127
}
128128

129129
@Override
130-
public ServerResponse.BodyBuilder eTag(String eTag) {
131-
Assert.notNull(eTag, "etag must not be null");
132-
eTag = ETag.quoteETagIfNecessary(eTag);
133-
this.headers.setETag(eTag);
130+
public ServerResponse.BodyBuilder eTag(String tag) {
131+
this.headers.setETag(tag);
134132
return this;
135133
}
136134

0 commit comments

Comments
 (0)