Skip to content

Commit 1b26122

Browse files
committed
Polishing and minor refactoring
Update checks whether quoting is needed to be more complete than what we've used so far, making sure the there is both opening and closing quotes independent of each other. See gh-33412
1 parent 80b264b commit 1b26122

File tree

6 files changed

+69
-33
lines changed

6 files changed

+69
-33
lines changed

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

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,27 @@ public static List<ETag> parse(String source) {
134134
return result;
135135
}
136136

137-
public static String format(String etag) {
138-
if (!etag.startsWith("\"") && !etag.startsWith("W/\"")) {
139-
etag = "\"" + etag;
137+
/**
138+
* Add quotes around the ETag value if not present already.
139+
* @param tag the ETag value
140+
* @return the resulting, quoted value
141+
* @since 6.2
142+
*/
143+
public static String quoteETagIfNecessary(String tag) {
144+
if (tag.startsWith("W/\"")) {
145+
if (tag.length() > 3 && tag.endsWith("\"")) {
146+
return tag;
147+
}
140148
}
141-
if (!etag.endsWith("\"")) {
142-
etag = etag + "\"";
149+
else if (tag.startsWith("\"")) {
150+
if (tag.length() > 1 && tag.endsWith("\"")) {
151+
return tag;
152+
}
143153
}
144-
return etag;
154+
return ("\"" + tag + "\"");
145155
}
146156

157+
147158
private enum State {
148159

149160
BEFORE_QUOTES, IN_QUOTES, AFTER_QUOTES

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

Lines changed: 4 additions & 6 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.
@@ -568,11 +568,9 @@ public BodyBuilder contentType(MediaType contentType) {
568568
}
569569

570570
@Override
571-
public BodyBuilder eTag(@Nullable String etag) {
572-
if (etag != null) {
573-
etag = ETag.format(etag);
574-
}
575-
this.headers.setETag(etag);
571+
public BodyBuilder eTag(@Nullable String eTag) {
572+
eTag = (eTag != null ? ETag.quoteETagIfNecessary(eTag) : eTag);
573+
this.headers.setETag(eTag);
576574
return this;
577575
}
578576

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

Lines changed: 12 additions & 5 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.
@@ -28,10 +28,17 @@
2828
import java.util.Set;
2929
import java.util.function.Consumer;
3030

31-
import org.springframework.http.*;
3231
import reactor.core.publisher.Mono;
3332

3433
import org.springframework.core.codec.Hints;
34+
import org.springframework.http.CacheControl;
35+
import org.springframework.http.ETag;
36+
import org.springframework.http.HttpHeaders;
37+
import org.springframework.http.HttpMethod;
38+
import org.springframework.http.HttpStatus;
39+
import org.springframework.http.HttpStatusCode;
40+
import org.springframework.http.MediaType;
41+
import org.springframework.http.ResponseCookie;
3542
import org.springframework.http.codec.HttpMessageWriter;
3643
import org.springframework.http.server.reactive.ServerHttpRequest;
3744
import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -141,9 +148,9 @@ public EntityResponse.Builder<T> contentType(MediaType contentType) {
141148
}
142149

143150
@Override
144-
public EntityResponse.Builder<T> eTag(String etag) {
145-
etag = ETag.format(etag);
146-
this.headers.setETag(etag);
151+
public EntityResponse.Builder<T> eTag(String eTag) {
152+
eTag = ETag.quoteETagIfNecessary(eTag);
153+
this.headers.setETag(eTag);
147154
return this;
148155
}
149156

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,18 @@
3232
import java.util.function.Function;
3333

3434
import org.reactivestreams.Publisher;
35-
import org.springframework.http.*;
3635
import reactor.core.publisher.Mono;
3736

3837
import org.springframework.core.ParameterizedTypeReference;
3938
import org.springframework.core.codec.Hints;
39+
import org.springframework.http.CacheControl;
40+
import org.springframework.http.ETag;
41+
import org.springframework.http.HttpHeaders;
42+
import org.springframework.http.HttpMethod;
43+
import org.springframework.http.HttpStatusCode;
44+
import org.springframework.http.MediaType;
45+
import org.springframework.http.ReactiveHttpOutputMessage;
46+
import org.springframework.http.ResponseCookie;
4047
import org.springframework.http.codec.HttpMessageWriter;
4148
import org.springframework.http.server.reactive.ServerHttpRequest;
4249
import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -140,10 +147,10 @@ public ServerResponse.BodyBuilder contentType(MediaType contentType) {
140147
}
141148

142149
@Override
143-
public ServerResponse.BodyBuilder eTag(String etag) {
144-
Assert.notNull(etag, "etag must not be null");
145-
etag = ETag.format(etag);
146-
this.headers.setETag(etag);
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);
147154
return this;
148155
}
149156

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

Lines changed: 13 additions & 5 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.
@@ -45,7 +45,15 @@
4545
import org.springframework.core.io.InputStreamResource;
4646
import org.springframework.core.io.Resource;
4747
import org.springframework.core.io.support.ResourceRegion;
48-
import org.springframework.http.*;
48+
import org.springframework.http.CacheControl;
49+
import org.springframework.http.ETag;
50+
import org.springframework.http.HttpHeaders;
51+
import org.springframework.http.HttpMethod;
52+
import org.springframework.http.HttpRange;
53+
import org.springframework.http.HttpStatus;
54+
import org.springframework.http.HttpStatusCode;
55+
import org.springframework.http.InvalidMediaTypeException;
56+
import org.springframework.http.MediaType;
4957
import org.springframework.http.converter.GenericHttpMessageConverter;
5058
import org.springframework.http.converter.HttpMessageConverter;
5159
import org.springframework.http.converter.SmartHttpMessageConverter;
@@ -158,9 +166,9 @@ public EntityResponse.Builder<T> contentType(MediaType contentType) {
158166
}
159167

160168
@Override
161-
public EntityResponse.Builder<T> eTag(String etag) {
162-
etag = ETag.format(etag);
163-
this.headers.setETag(etag);
169+
public EntityResponse.Builder<T> eTag(String eTag) {
170+
eTag = ETag.quoteETagIfNecessary(eTag);
171+
this.headers.setETag(eTag);
164172
return this;
165173
}
166174

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

Lines changed: 11 additions & 6 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.
@@ -30,7 +30,12 @@
3030
import jakarta.servlet.http.HttpServletResponse;
3131

3232
import org.springframework.core.ParameterizedTypeReference;
33-
import org.springframework.http.*;
33+
import org.springframework.http.CacheControl;
34+
import org.springframework.http.ETag;
35+
import org.springframework.http.HttpHeaders;
36+
import org.springframework.http.HttpMethod;
37+
import org.springframework.http.HttpStatusCode;
38+
import org.springframework.http.MediaType;
3439
import org.springframework.lang.Nullable;
3540
import org.springframework.util.Assert;
3641
import org.springframework.util.LinkedMultiValueMap;
@@ -122,10 +127,10 @@ public ServerResponse.BodyBuilder contentType(MediaType contentType) {
122127
}
123128

124129
@Override
125-
public ServerResponse.BodyBuilder eTag(String etag) {
126-
Assert.notNull(etag, "etag must not be null");
127-
etag = ETag.format(etag);
128-
this.headers.setETag(etag);
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);
129134
return this;
130135
}
131136

0 commit comments

Comments
 (0)