Consistent comma splitting without regex overhead
Issue: SPR-14635
(cherry picked from commit 03609c1)
This commit is contained in:
parent
3b91dec462
commit
d8f7347000
|
|
@ -277,7 +277,7 @@ public abstract class MimeTypeUtils {
|
|||
if (!StringUtils.hasLength(mimeTypes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String[] tokens = mimeTypes.split(",\\s*");
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(mimeTypes, ",");
|
||||
List<MimeType> result = new ArrayList<MimeType>(tokens.length);
|
||||
for (String token : tokens) {
|
||||
result.add(parseMimeType(token));
|
||||
|
|
|
|||
|
|
@ -228,10 +228,10 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
|
|||
|
||||
public long[] getHeartbeat() {
|
||||
String rawValue = getFirstNativeHeader(STOMP_HEARTBEAT_HEADER);
|
||||
if (!StringUtils.hasText(rawValue)) {
|
||||
String[] rawValues = StringUtils.split(rawValue, ",");
|
||||
if (rawValues == null) {
|
||||
return Arrays.copyOf(DEFAULT_HEARTBEAT, 2);
|
||||
}
|
||||
String[] rawValues = StringUtils.commaDelimitedListToStringArray(rawValue);
|
||||
return new long[] {Long.valueOf(rawValues[0]), Long.valueOf(rawValues[1])};
|
||||
}
|
||||
|
||||
|
|
@ -297,7 +297,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
|
|||
}
|
||||
|
||||
public void setHeartbeat(long cx, long cy) {
|
||||
setNativeHeader(STOMP_HEARTBEAT_HEADER, StringUtils.arrayToCommaDelimitedString(new Object[]{cx, cy}));
|
||||
setNativeHeader(STOMP_HEARTBEAT_HEADER, cx + "," + cy);
|
||||
}
|
||||
|
||||
public void setAck(String ack) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
|
@ -223,9 +223,14 @@ public class StompHeaders implements MultiValueMap<String, String>, Serializable
|
|||
* Applies to the CONNECT and CONNECTED frames.
|
||||
*/
|
||||
public void setHeartbeat(long[] heartbeat) {
|
||||
Assert.notNull(heartbeat);
|
||||
if (heartbeat == null || heartbeat.length != 2) {
|
||||
throw new IllegalArgumentException("Heart-beat array must be of length 2, not " +
|
||||
(heartbeat != null ? heartbeat.length : "null"));
|
||||
}
|
||||
String value = heartbeat[0] + "," + heartbeat[1];
|
||||
Assert.isTrue(heartbeat[0] >= 0 && heartbeat[1] >= 0, "Heart-beat values cannot be negative: " + value);
|
||||
if (heartbeat[0] < 0 || heartbeat[1] < 0) {
|
||||
throw new IllegalArgumentException("Heart-beat values cannot be negative: " + value);
|
||||
}
|
||||
set(HEARTBEAT, value);
|
||||
}
|
||||
|
||||
|
|
@ -234,10 +239,10 @@ public class StompHeaders implements MultiValueMap<String, String>, Serializable
|
|||
*/
|
||||
public long[] getHeartbeat() {
|
||||
String rawValue = getFirst(HEARTBEAT);
|
||||
if (!StringUtils.hasText(rawValue)) {
|
||||
String[] rawValues = StringUtils.split(rawValue, ",");
|
||||
if (rawValues == null) {
|
||||
return null;
|
||||
}
|
||||
String[] rawValues = StringUtils.commaDelimitedListToStringArray(rawValue);
|
||||
return new long[] {Long.valueOf(rawValues[0]), Long.valueOf(rawValues[1])};
|
||||
}
|
||||
|
||||
|
|
@ -497,14 +502,8 @@ public class StompHeaders implements MultiValueMap<String, String>, Serializable
|
|||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof StompHeaders)) {
|
||||
return false;
|
||||
}
|
||||
StompHeaders otherHeaders = (StompHeaders) other;
|
||||
return this.headers.equals(otherHeaders.headers);
|
||||
return (this == other || (other instanceof StompHeaders &&
|
||||
this.headers.equals(((StompHeaders) other).headers)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
|||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
|
|
@ -198,7 +199,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable {
|
|||
* {@link HttpServletRequest#getContextPath()} which states it can be
|
||||
* an empty string, or it must start with a "/" and not end with a "/".
|
||||
* @param contextPath a valid contextPath
|
||||
* @throws IllegalArgumentException if the contextPath is not a valid {@link HttpServletRequest#getContextPath()}
|
||||
* @throws IllegalArgumentException if the contextPath is not a valid
|
||||
* {@link HttpServletRequest#getContextPath()}
|
||||
*/
|
||||
public void setContextPath(String contextPath) {
|
||||
MockMvcWebConnection.validateContextPath(contextPath);
|
||||
|
|
@ -211,9 +213,9 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable {
|
|||
|
||||
private void authType(MockHttpServletRequest request) {
|
||||
String authorization = header("Authorization");
|
||||
if (authorization != null) {
|
||||
String[] authzParts = authorization.split(": ");
|
||||
request.setAuthType(authzParts[0]);
|
||||
String[] authSplit = StringUtils.split(authorization, ": ");
|
||||
if (authSplit != null) {
|
||||
request.setAuthType(authSplit[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,8 +265,8 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable {
|
|||
while (tokens.hasMoreTokens()) {
|
||||
String cookieName = tokens.nextToken().trim();
|
||||
if (!tokens.hasMoreTokens()) {
|
||||
throw new IllegalArgumentException("Expected value for cookie name '" + cookieName
|
||||
+ "'. Full cookie was " + cookieHeaderValue);
|
||||
throw new IllegalArgumentException("Expected value for cookie name '" + cookieName +
|
||||
"'. Full cookie was " + cookieHeaderValue);
|
||||
}
|
||||
String cookieValue = tokens.nextToken().trim();
|
||||
processCookie(request, cookies, new Cookie(cookieName, cookieValue));
|
||||
|
|
@ -352,9 +354,9 @@ final class HtmlUnitRequestBuilder implements RequestBuilder, Mergeable {
|
|||
request.addPreferredLocale(Locale.getDefault());
|
||||
}
|
||||
else {
|
||||
String[] locales = locale.split(", ");
|
||||
for (int i = locales.length - 1; i >= 0; i--) {
|
||||
request.addPreferredLocale(parseLocale(locales[i]));
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(locale, ",");
|
||||
for (int i = tokens.length - 1; i >= 0; i--) {
|
||||
request.addPreferredLocale(parseLocale(tokens[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
List<HttpMethod> result = new ArrayList<HttpMethod>();
|
||||
String value = getFirst(ACCESS_CONTROL_ALLOW_METHODS);
|
||||
if (value != null) {
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(value, ",", true, true);
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(value, ",");
|
||||
for (String token : tokens) {
|
||||
HttpMethod resolved = HttpMethod.resolve(token);
|
||||
if (resolved != null) {
|
||||
|
|
@ -578,10 +578,10 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
* as specified by the {@code Accept-Charset} header.
|
||||
*/
|
||||
public List<Charset> getAcceptCharset() {
|
||||
List<Charset> result = new ArrayList<Charset>();
|
||||
String value = getFirst(ACCEPT_CHARSET);
|
||||
if (value != null) {
|
||||
String[] tokens = value.split(",\\s*");
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(value, ",");
|
||||
List<Charset> result = new ArrayList<Charset>(tokens.length);
|
||||
for (String token : tokens) {
|
||||
int paramIdx = token.indexOf(';');
|
||||
String charsetName;
|
||||
|
|
@ -595,8 +595,11 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
result.add(Charset.forName(charsetName));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -615,8 +618,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
public Set<HttpMethod> getAllow() {
|
||||
String value = getFirst(ALLOW);
|
||||
if (!StringUtils.isEmpty(value)) {
|
||||
List<HttpMethod> result = new LinkedList<HttpMethod>();
|
||||
String[] tokens = value.split(",\\s*");
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(value, ",");
|
||||
List<HttpMethod> result = new ArrayList<HttpMethod>(tokens.length);
|
||||
for (String token : tokens) {
|
||||
HttpMethod resolved = HttpMethod.resolve(token);
|
||||
if (resolved != null) {
|
||||
|
|
@ -691,7 +694,7 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
StringBuilder builder = new StringBuilder("form-data; name=\"");
|
||||
builder.append(name).append('\"');
|
||||
if (filename != null) {
|
||||
if(charset == null || Charset.forName("US-ASCII").equals(charset)) {
|
||||
if (charset == null || charset.name().equals("US-ASCII")) {
|
||||
builder.append("; filename=\"");
|
||||
builder.append(filename).append('\"');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ public abstract class HttpRange {
|
|||
}
|
||||
ranges = ranges.substring(BYTE_RANGE_PREFIX.length());
|
||||
|
||||
String[] tokens = ranges.split(",\\s*");
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(ranges, ",");
|
||||
List<HttpRange> result = new ArrayList<HttpRange>(tokens.length);
|
||||
for (String token : tokens) {
|
||||
result.add(parseRange(token));
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ public class MediaType extends MimeType implements Serializable {
|
|||
if (!StringUtils.hasLength(mediaTypes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String[] tokens = mediaTypes.split(",\\s*");
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(mediaTypes, ",");
|
||||
List<MediaType> result = new ArrayList<MediaType>(tokens.length);
|
||||
for (String token : tokens) {
|
||||
result.add(parseMediaType(token));
|
||||
|
|
|
|||
|
|
@ -673,7 +673,7 @@ public class UriComponentsBuilder implements Cloneable {
|
|||
UriComponentsBuilder adaptFromForwardedHeaders(HttpHeaders headers) {
|
||||
String forwardedHeader = headers.getFirst("Forwarded");
|
||||
if (StringUtils.hasText(forwardedHeader)) {
|
||||
String forwardedToUse = StringUtils.commaDelimitedListToStringArray(forwardedHeader)[0];
|
||||
String forwardedToUse = StringUtils.tokenizeToStringArray(forwardedHeader, ",")[0];
|
||||
Matcher matcher = FORWARDED_HOST_PATTERN.matcher(forwardedToUse);
|
||||
if (matcher.find()) {
|
||||
host(matcher.group(1).trim());
|
||||
|
|
@ -686,10 +686,9 @@ public class UriComponentsBuilder implements Cloneable {
|
|||
else {
|
||||
String hostHeader = headers.getFirst("X-Forwarded-Host");
|
||||
if (StringUtils.hasText(hostHeader)) {
|
||||
String[] hosts = StringUtils.commaDelimitedListToStringArray(hostHeader);
|
||||
String hostToUse = hosts[0];
|
||||
if (hostToUse.contains(":")) {
|
||||
String[] hostAndPort = StringUtils.split(hostToUse, ":");
|
||||
String hostToUse = StringUtils.tokenizeToStringArray(hostHeader, ",")[0];
|
||||
String[] hostAndPort = StringUtils.split(hostToUse, ":");
|
||||
if (hostAndPort != null) {
|
||||
host(hostAndPort[0]);
|
||||
port(Integer.parseInt(hostAndPort[1]));
|
||||
}
|
||||
|
|
@ -701,14 +700,12 @@ public class UriComponentsBuilder implements Cloneable {
|
|||
|
||||
String portHeader = headers.getFirst("X-Forwarded-Port");
|
||||
if (StringUtils.hasText(portHeader)) {
|
||||
String[] ports = StringUtils.commaDelimitedListToStringArray(portHeader);
|
||||
port(Integer.parseInt(ports[0]));
|
||||
port(Integer.parseInt(StringUtils.tokenizeToStringArray(portHeader, ",")[0]));
|
||||
}
|
||||
|
||||
String protocolHeader = headers.getFirst("X-Forwarded-Proto");
|
||||
if (StringUtils.hasText(protocolHeader)) {
|
||||
String[] protocols = StringUtils.commaDelimitedListToStringArray(protocolHeader);
|
||||
scheme(protocols[0]);
|
||||
scheme(StringUtils.tokenizeToStringArray(protocolHeader, ",")[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
|
@ -44,6 +44,7 @@ import org.springframework.util.StringUtils;
|
|||
* e.g. extensions "foo, bar" will be executed as "bar(foo(message))".</p>
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-9">WebSocket Protocol Extensions, RFC 6455 - Section 9</a>
|
||||
*/
|
||||
|
|
@ -68,54 +69,90 @@ public class WebSocketExtension {
|
|||
* @param parameters the parameters
|
||||
*/
|
||||
public WebSocketExtension(String name, Map<String, String> parameters) {
|
||||
Assert.hasLength(name, "extension name must not be empty");
|
||||
Assert.hasLength(name, "Extension name must not be empty");
|
||||
this.name = name;
|
||||
if (!CollectionUtils.isEmpty(parameters)) {
|
||||
Map<String, String> m = new LinkedCaseInsensitiveMap<String>(parameters.size(), Locale.ENGLISH);
|
||||
m.putAll(parameters);
|
||||
this.parameters = Collections.unmodifiableMap(m);
|
||||
Map<String, String> map = new LinkedCaseInsensitiveMap<String>(parameters.size(), Locale.ENGLISH);
|
||||
map.putAll(parameters);
|
||||
this.parameters = Collections.unmodifiableMap(map);
|
||||
}
|
||||
else {
|
||||
this.parameters = Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name of the extension
|
||||
* Return the name of the extension (never {@code null) or empty}.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parameters of the extension, never {@code null}
|
||||
* Return the parameters of the extension (never {@code null}).
|
||||
*/
|
||||
public Map<String, String> getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return false;
|
||||
}
|
||||
WebSocketExtension otherExt = (WebSocketExtension) other;
|
||||
return (this.name.equals(otherExt.name) && this.parameters.equals(otherExt.parameters));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.name.hashCode() * 31 + this.parameters.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(this.name);
|
||||
for (Map.Entry<String, String> entry : this.parameters.entrySet()) {
|
||||
str.append(';');
|
||||
str.append(entry.getKey());
|
||||
str.append('=');
|
||||
str.append(entry.getValue());
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the given, comma-separated string into a list of {@code WebSocketExtension} objects.
|
||||
* <p>This method can be used to parse a "Sec-WebSocket-Extension" extensions.
|
||||
* <p>This method can be used to parse a "Sec-WebSocket-Extension" header.
|
||||
* @param extensions the string to parse
|
||||
* @return the list of extensions
|
||||
* @throws IllegalArgumentException if the string cannot be parsed
|
||||
*/
|
||||
public static List<WebSocketExtension> parseExtensions(String extensions) {
|
||||
if (extensions == null || !StringUtils.hasText(extensions)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
List<WebSocketExtension> result = new ArrayList<WebSocketExtension>();
|
||||
for (String token : extensions.split(",")) {
|
||||
if (StringUtils.hasText(extensions)) {
|
||||
String[] tokens = StringUtils.tokenizeToStringArray(extensions, ",");
|
||||
List<WebSocketExtension> result = new ArrayList<WebSocketExtension>(tokens.length);
|
||||
for (String token : StringUtils.tokenizeToStringArray(extensions, ",")) {
|
||||
result.add(parseExtension(token));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static WebSocketExtension parseExtension(String extension) {
|
||||
Assert.doesNotContain(extension, ",", "Expected a single extension value: " + extension);
|
||||
if (extension.contains(",")) {
|
||||
throw new IllegalArgumentException("Expected single extension value: [" + extension + "]");
|
||||
}
|
||||
String[] parts = StringUtils.tokenizeToStringArray(extension, ";");
|
||||
String name = parts[0].trim();
|
||||
|
||||
|
|
@ -136,42 +173,4 @@ public class WebSocketExtension {
|
|||
return new WebSocketExtension(name, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if ((o == null) || (getClass() != o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
WebSocketExtension that = (WebSocketExtension) o;
|
||||
if (!name.equals(that.name)) {
|
||||
return false;
|
||||
}
|
||||
if (!parameters.equals(that.parameters)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + parameters.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(this.name);
|
||||
for (String param : parameters.keySet()) {
|
||||
str.append(';');
|
||||
str.append(param);
|
||||
str.append('=');
|
||||
str.append(this.parameters.get(param));
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public abstract class AbstractTyrusRequestUpgradeStrategy extends AbstractStanda
|
|||
|
||||
@Override
|
||||
public String[] getSupportedVersions() {
|
||||
return StringUtils.commaDelimitedListToStringArray(Version.getSupportedWireProtocolVersions());
|
||||
return StringUtils.tokenizeToStringArray(Version.getSupportedWireProtocolVersions(), ",");
|
||||
}
|
||||
|
||||
protected List<WebSocketExtension> getInstalledExtensions(WebSocketContainer container) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue