Skip to content

Commit 03609c1

Browse files
committed
Consistent comma splitting without regex overhead
Issue: SPR-14635
1 parent 58fa63f commit 03609c1

File tree

10 files changed

+84
-87
lines changed

10 files changed

+84
-87
lines changed

spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ public static List<MimeType> parseMimeTypes(String mimeTypes) {
274274
if (!StringUtils.hasLength(mimeTypes)) {
275275
return Collections.emptyList();
276276
}
277-
String[] tokens = mimeTypes.split(",\\s*");
277+
String[] tokens = StringUtils.tokenizeToStringArray(mimeTypes, ",");
278278
List<MimeType> result = new ArrayList<>(tokens.length);
279279
for (String token : tokens) {
280280
result.add(parseMimeType(token));

spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaderAccessor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,10 @@ public boolean isHeartbeat() {
229229

230230
public long[] getHeartbeat() {
231231
String rawValue = getFirstNativeHeader(STOMP_HEARTBEAT_HEADER);
232-
if (!StringUtils.hasText(rawValue)) {
232+
String[] rawValues = StringUtils.split(rawValue, ",");
233+
if (rawValues == null) {
233234
return Arrays.copyOf(DEFAULT_HEARTBEAT, 2);
234235
}
235-
String[] rawValues = StringUtils.commaDelimitedListToStringArray(rawValue);
236236
return new long[] {Long.valueOf(rawValues[0]), Long.valueOf(rawValues[1])};
237237
}
238238

@@ -298,7 +298,7 @@ public void setContentLength(int contentLength) {
298298
}
299299

300300
public void setHeartbeat(long cx, long cy) {
301-
setNativeHeader(STOMP_HEARTBEAT_HEADER, StringUtils.arrayToCommaDelimitedString(new Object[]{cx, cy}));
301+
setNativeHeader(STOMP_HEARTBEAT_HEADER, cx + "," + cy);
302302
}
303303

304304
public void setAck(String ack) {

spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompHeaders.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,14 @@ public String getPasscode() {
223223
* Applies to the CONNECT and CONNECTED frames.
224224
*/
225225
public void setHeartbeat(long[] heartbeat) {
226-
Assert.notNull(heartbeat);
226+
if (heartbeat == null || heartbeat.length != 2) {
227+
throw new IllegalArgumentException("Heart-beat array must be of length 2, not " +
228+
(heartbeat != null ? heartbeat.length : "null"));
229+
}
227230
String value = heartbeat[0] + "," + heartbeat[1];
228-
Assert.isTrue(heartbeat[0] >= 0 && heartbeat[1] >= 0, "Heart-beat values cannot be negative: " + value);
231+
if (heartbeat[0] < 0 || heartbeat[1] < 0) {
232+
throw new IllegalArgumentException("Heart-beat values cannot be negative: " + value);
233+
}
229234
set(HEARTBEAT, value);
230235
}
231236

@@ -234,10 +239,10 @@ public void setHeartbeat(long[] heartbeat) {
234239
*/
235240
public long[] getHeartbeat() {
236241
String rawValue = getFirst(HEARTBEAT);
237-
if (!StringUtils.hasText(rawValue)) {
242+
String[] rawValues = StringUtils.split(rawValue, ",");
243+
if (rawValues == null) {
238244
return null;
239245
}
240-
String[] rawValues = StringUtils.commaDelimitedListToStringArray(rawValue);
241246
return new long[] {Long.valueOf(rawValues[0]), Long.valueOf(rawValues[1])};
242247
}
243248

@@ -497,14 +502,8 @@ public Set<Entry<String, List<String>>> entrySet() {
497502

498503
@Override
499504
public boolean equals(Object other) {
500-
if (this == other) {
501-
return true;
502-
}
503-
if (!(other instanceof StompHeaders)) {
504-
return false;
505-
}
506-
StompHeaders otherHeaders = (StompHeaders) other;
507-
return this.headers.equals(otherHeaders.headers);
505+
return (this == other || (other instanceof StompHeaders &&
506+
this.headers.equals(((StompHeaders) other).headers)));
508507
}
509508

510509
@Override

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/HtmlUnitRequestBuilder.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.springframework.test.web.servlet.request.RequestPostProcessor;
5151
import org.springframework.util.Assert;
5252
import org.springframework.util.ObjectUtils;
53+
import org.springframework.util.StringUtils;
5354
import org.springframework.web.util.UriComponents;
5455
import org.springframework.web.util.UriComponentsBuilder;
5556

@@ -213,8 +214,7 @@ public void setForwardPostProcessor(RequestPostProcessor forwardPostProcessor) {
213214
private void authType(MockHttpServletRequest request) {
214215
String authorization = header("Authorization");
215216
if (authorization != null) {
216-
String[] authzParts = authorization.split(": ");
217-
request.setAuthType(authzParts[0]);
217+
request.setAuthType(StringUtils.split(authorization, ": ")[0]);
218218
}
219219
}
220220

@@ -349,9 +349,9 @@ private void locales(MockHttpServletRequest request) {
349349
request.addPreferredLocale(Locale.getDefault());
350350
}
351351
else {
352-
String[] locales = locale.split(", ");
353-
for (int i = locales.length - 1; i >= 0; i--) {
354-
request.addPreferredLocale(parseLocale(locales[i]));
352+
String[] tokens = StringUtils.tokenizeToStringArray(locale, ",");
353+
for (int i = tokens.length - 1; i >= 0; i--) {
354+
request.addPreferredLocale(parseLocale(tokens[i]));
355355
}
356356
}
357357
}

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ public List<HttpMethod> getAccessControlAllowMethods() {
476476
List<HttpMethod> result = new ArrayList<>();
477477
String value = getFirst(ACCESS_CONTROL_ALLOW_METHODS);
478478
if (value != null) {
479-
String[] tokens = StringUtils.tokenizeToStringArray(value, ",", true, true);
479+
String[] tokens = StringUtils.tokenizeToStringArray(value, ",");
480480
for (String token : tokens) {
481481
HttpMethod resolved = HttpMethod.resolve(token);
482482
if (resolved != null) {
@@ -580,10 +580,10 @@ public void setAcceptCharset(List<Charset> acceptableCharsets) {
580580
* as specified by the {@code Accept-Charset} header.
581581
*/
582582
public List<Charset> getAcceptCharset() {
583-
List<Charset> result = new ArrayList<>();
584583
String value = getFirst(ACCEPT_CHARSET);
585584
if (value != null) {
586-
String[] tokens = value.split(",\\s*");
585+
String[] tokens = StringUtils.tokenizeToStringArray(value, ",");
586+
List<Charset> result = new ArrayList<>(tokens.length);
587587
for (String token : tokens) {
588588
int paramIdx = token.indexOf(';');
589589
String charsetName;
@@ -597,8 +597,11 @@ public List<Charset> getAcceptCharset() {
597597
result.add(Charset.forName(charsetName));
598598
}
599599
}
600+
return result;
601+
}
602+
else {
603+
return Collections.emptyList();
600604
}
601-
return result;
602605
}
603606

604607
/**
@@ -617,8 +620,8 @@ public void setAllow(Set<HttpMethod> allowedMethods) {
617620
public Set<HttpMethod> getAllow() {
618621
String value = getFirst(ALLOW);
619622
if (!StringUtils.isEmpty(value)) {
620-
List<HttpMethod> result = new LinkedList<>();
621-
String[] tokens = value.split(",\\s*");
623+
String[] tokens = StringUtils.tokenizeToStringArray(value, ",");
624+
List<HttpMethod> result = new ArrayList<>(tokens.length);
622625
for (String token : tokens) {
623626
HttpMethod resolved = HttpMethod.resolve(token);
624627
if (resolved != null) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public static List<HttpRange> parseRanges(String ranges) {
132132
}
133133
ranges = ranges.substring(BYTE_RANGE_PREFIX.length());
134134

135-
String[] tokens = ranges.split(",\\s*");
135+
String[] tokens = StringUtils.tokenizeToStringArray(ranges, ",");
136136
List<HttpRange> result = new ArrayList<>(tokens.length);
137137
for (String token : tokens) {
138138
result.add(parseRange(token));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ public static List<MediaType> parseMediaTypes(String mediaTypes) {
439439
if (!StringUtils.hasLength(mediaTypes)) {
440440
return Collections.emptyList();
441441
}
442-
String[] tokens = mediaTypes.split(",\\s*");
442+
String[] tokens = StringUtils.tokenizeToStringArray(mediaTypes, ",");
443443
List<MediaType> result = new ArrayList<>(tokens.length);
444444
for (String token : tokens) {
445445
result.add(parseMediaType(token));

spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ public UriComponentsBuilder fragment(String fragment) {
673673
UriComponentsBuilder adaptFromForwardedHeaders(HttpHeaders headers) {
674674
String forwardedHeader = headers.getFirst("Forwarded");
675675
if (StringUtils.hasText(forwardedHeader)) {
676-
String forwardedToUse = StringUtils.commaDelimitedListToStringArray(forwardedHeader)[0];
676+
String forwardedToUse = StringUtils.tokenizeToStringArray(forwardedHeader, ",")[0];
677677
Matcher matcher = FORWARDED_HOST_PATTERN.matcher(forwardedToUse);
678678
if (matcher.find()) {
679679
host(matcher.group(1).trim());
@@ -686,10 +686,9 @@ UriComponentsBuilder adaptFromForwardedHeaders(HttpHeaders headers) {
686686
else {
687687
String hostHeader = headers.getFirst("X-Forwarded-Host");
688688
if (StringUtils.hasText(hostHeader)) {
689-
String[] hosts = StringUtils.commaDelimitedListToStringArray(hostHeader);
690-
String hostToUse = hosts[0];
691-
if (hostToUse.contains(":")) {
692-
String[] hostAndPort = StringUtils.split(hostToUse, ":");
689+
String hostToUse = StringUtils.tokenizeToStringArray(hostHeader, ",")[0];
690+
String[] hostAndPort = StringUtils.split(hostToUse, ":");
691+
if (hostAndPort != null) {
693692
host(hostAndPort[0]);
694693
port(Integer.parseInt(hostAndPort[1]));
695694
}
@@ -701,14 +700,12 @@ UriComponentsBuilder adaptFromForwardedHeaders(HttpHeaders headers) {
701700

702701
String portHeader = headers.getFirst("X-Forwarded-Port");
703702
if (StringUtils.hasText(portHeader)) {
704-
String[] ports = StringUtils.commaDelimitedListToStringArray(portHeader);
705-
port(Integer.parseInt(ports[0]));
703+
port(Integer.parseInt(StringUtils.tokenizeToStringArray(portHeader, ",")[0]));
706704
}
707705

708706
String protocolHeader = headers.getFirst("X-Forwarded-Proto");
709707
if (StringUtils.hasText(protocolHeader)) {
710-
String[] protocols = StringUtils.commaDelimitedListToStringArray(protocolHeader);
711-
scheme(protocols[0]);
708+
scheme(StringUtils.tokenizeToStringArray(protocolHeader, ",")[0]);
712709
}
713710
}
714711

spring-websocket/src/main/java/org/springframework/web/socket/WebSocketExtension.java

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
* e.g. extensions "foo, bar" will be executed as "bar(foo(message))".</p>
4545
*
4646
* @author Brian Clozel
47+
* @author Juergen Hoeller
4748
* @since 4.0
4849
* @see <a href="https://tools.ietf.org/html/rfc6455#section-9">WebSocket Protocol Extensions, RFC 6455 - Section 9</a>
4950
*/
@@ -68,54 +69,89 @@ public WebSocketExtension(String name) {
6869
* @param parameters the parameters
6970
*/
7071
public WebSocketExtension(String name, Map<String, String> parameters) {
71-
Assert.hasLength(name, "extension name must not be empty");
72+
Assert.hasLength(name, "Extension name must not be empty");
7273
this.name = name;
7374
if (!CollectionUtils.isEmpty(parameters)) {
74-
Map<String, String> m = new LinkedCaseInsensitiveMap<>(parameters.size(), Locale.ENGLISH);
75-
m.putAll(parameters);
76-
this.parameters = Collections.unmodifiableMap(m);
75+
Map<String, String> map = new LinkedCaseInsensitiveMap<>(parameters.size(), Locale.ENGLISH);
76+
map.putAll(parameters);
77+
this.parameters = Collections.unmodifiableMap(map);
7778
}
7879
else {
7980
this.parameters = Collections.emptyMap();
8081
}
8182
}
8283

84+
8385
/**
84-
* @return the name of the extension
86+
* Return the name of the extension (never {@code null) or empty}.
8587
*/
8688
public String getName() {
8789
return this.name;
8890
}
8991

9092
/**
91-
* @return the parameters of the extension, never {@code null}
93+
* Return the parameters of the extension (never {@code null}).
9294
*/
9395
public Map<String, String> getParameters() {
9496
return this.parameters;
9597
}
9698

99+
100+
@Override
101+
public boolean equals(Object other) {
102+
if (this == other) {
103+
return true;
104+
}
105+
if (other == null || getClass() != other.getClass()) {
106+
return false;
107+
}
108+
WebSocketExtension otherExt = (WebSocketExtension) other;
109+
return (this.name.equals(otherExt.name) && this.parameters.equals(otherExt.parameters));
110+
}
111+
112+
@Override
113+
public int hashCode() {
114+
return this.name.hashCode() * 31 + this.parameters.hashCode();
115+
}
116+
117+
@Override
118+
public String toString() {
119+
StringBuilder str = new StringBuilder();
120+
str.append(this.name);
121+
for (String param : parameters.keySet()) {
122+
str.append(';');
123+
str.append(param);
124+
str.append('=');
125+
str.append(this.parameters.get(param));
126+
}
127+
return str.toString();
128+
}
129+
130+
97131
/**
98132
* Parse the given, comma-separated string into a list of {@code WebSocketExtension} objects.
99-
* <p>This method can be used to parse a "Sec-WebSocket-Extension" extensions.
133+
* <p>This method can be used to parse a "Sec-WebSocket-Extension" header.
100134
* @param extensions the string to parse
101135
* @return the list of extensions
102136
* @throws IllegalArgumentException if the string cannot be parsed
103137
*/
104138
public static List<WebSocketExtension> parseExtensions(String extensions) {
105-
if (extensions == null || !StringUtils.hasText(extensions)) {
139+
if (!StringUtils.hasText(extensions)) {
106140
return Collections.emptyList();
107141
}
108142
else {
109143
List<WebSocketExtension> result = new ArrayList<>();
110-
for (String token : extensions.split(",")) {
144+
for (String token : StringUtils.tokenizeToStringArray(extensions, ",")) {
111145
result.add(parseExtension(token));
112146
}
113147
return result;
114148
}
115149
}
116150

117151
private static WebSocketExtension parseExtension(String extension) {
118-
Assert.doesNotContain(extension, ",", "Expected a single extension value: " + extension);
152+
if (extension.contains(",")) {
153+
throw new IllegalArgumentException("Expected single extension value: [" + extension + "]");
154+
}
119155
String[] parts = StringUtils.tokenizeToStringArray(extension, ";");
120156
String name = parts[0].trim();
121157

@@ -136,42 +172,4 @@ private static WebSocketExtension parseExtension(String extension) {
136172
return new WebSocketExtension(name, parameters);
137173
}
138174

139-
@Override
140-
public boolean equals(Object o) {
141-
if (this == o) {
142-
return true;
143-
}
144-
if ((o == null) || (getClass() != o.getClass())) {
145-
return false;
146-
}
147-
WebSocketExtension that = (WebSocketExtension) o;
148-
if (!name.equals(that.name)) {
149-
return false;
150-
}
151-
if (!parameters.equals(that.parameters)) {
152-
return false;
153-
}
154-
return true;
155-
}
156-
157-
@Override
158-
public int hashCode() {
159-
int result = name.hashCode();
160-
result = 31 * result + parameters.hashCode();
161-
return result;
162-
}
163-
164-
@Override
165-
public String toString() {
166-
StringBuilder str = new StringBuilder();
167-
str.append(this.name);
168-
for (String param : parameters.keySet()) {
169-
str.append(';');
170-
str.append(param);
171-
str.append('=');
172-
str.append(this.parameters.get(param));
173-
}
174-
return str.toString();
175-
}
176-
177175
}

spring-websocket/src/main/java/org/springframework/web/socket/server/standard/AbstractTyrusRequestUpgradeStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ private static Constructor<?> getEndpointConstructor() {
110110

111111
@Override
112112
public String[] getSupportedVersions() {
113-
return StringUtils.commaDelimitedListToStringArray(Version.getSupportedWireProtocolVersions());
113+
return StringUtils.tokenizeToStringArray(Version.getSupportedWireProtocolVersions(), ",");
114114
}
115115

116116
protected List<WebSocketExtension> getInstalledExtensions(WebSocketContainer container) {

0 commit comments

Comments
 (0)