|
|
|
@ -44,6 +44,7 @@ import org.springframework.util.StringUtils; |
|
|
|
* e.g. extensions "foo, bar" will be executed as "bar(foo(message))".</p> |
|
|
|
* e.g. extensions "foo, bar" will be executed as "bar(foo(message))".</p> |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Brian Clozel |
|
|
|
* @author Brian Clozel |
|
|
|
|
|
|
|
* @author Juergen Hoeller |
|
|
|
* @since 4.0 |
|
|
|
* @since 4.0 |
|
|
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-9">WebSocket Protocol Extensions, RFC 6455 - Section 9</a> |
|
|
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-9">WebSocket Protocol Extensions, RFC 6455 - Section 9</a> |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -68,46 +69,79 @@ public class WebSocketExtension { |
|
|
|
* @param parameters the parameters |
|
|
|
* @param parameters the parameters |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public WebSocketExtension(String name, Map<String, String> 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; |
|
|
|
this.name = name; |
|
|
|
if (!CollectionUtils.isEmpty(parameters)) { |
|
|
|
if (!CollectionUtils.isEmpty(parameters)) { |
|
|
|
Map<String, String> m = new LinkedCaseInsensitiveMap<>(parameters.size(), Locale.ENGLISH); |
|
|
|
Map<String, String> map = new LinkedCaseInsensitiveMap<>(parameters.size(), Locale.ENGLISH); |
|
|
|
m.putAll(parameters); |
|
|
|
map.putAll(parameters); |
|
|
|
this.parameters = Collections.unmodifiableMap(m); |
|
|
|
this.parameters = Collections.unmodifiableMap(map); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
this.parameters = Collections.emptyMap(); |
|
|
|
this.parameters = Collections.emptyMap(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* @return the name of the extension |
|
|
|
* Return the name of the extension (never {@code null) or empty}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public String getName() { |
|
|
|
public String getName() { |
|
|
|
return this.name; |
|
|
|
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() { |
|
|
|
public Map<String, String> getParameters() { |
|
|
|
return this.parameters; |
|
|
|
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 (String param : parameters.keySet()) { |
|
|
|
|
|
|
|
str.append(';'); |
|
|
|
|
|
|
|
str.append(param); |
|
|
|
|
|
|
|
str.append('='); |
|
|
|
|
|
|
|
str.append(this.parameters.get(param)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return str.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Parse the given, comma-separated string into a list of {@code WebSocketExtension} objects. |
|
|
|
* 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 |
|
|
|
* @param extensions the string to parse |
|
|
|
* @return the list of extensions |
|
|
|
* @return the list of extensions |
|
|
|
* @throws IllegalArgumentException if the string cannot be parsed |
|
|
|
* @throws IllegalArgumentException if the string cannot be parsed |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static List<WebSocketExtension> parseExtensions(String extensions) { |
|
|
|
public static List<WebSocketExtension> parseExtensions(String extensions) { |
|
|
|
if (extensions == null || !StringUtils.hasText(extensions)) { |
|
|
|
if (!StringUtils.hasText(extensions)) { |
|
|
|
return Collections.emptyList(); |
|
|
|
return Collections.emptyList(); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
List<WebSocketExtension> result = new ArrayList<>(); |
|
|
|
List<WebSocketExtension> result = new ArrayList<>(); |
|
|
|
for (String token : extensions.split(",")) { |
|
|
|
for (String token : StringUtils.tokenizeToStringArray(extensions, ",")) { |
|
|
|
result.add(parseExtension(token)); |
|
|
|
result.add(parseExtension(token)); |
|
|
|
} |
|
|
|
} |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
@ -115,7 +149,9 @@ public class WebSocketExtension { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static WebSocketExtension parseExtension(String extension) { |
|
|
|
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[] parts = StringUtils.tokenizeToStringArray(extension, ";"); |
|
|
|
String name = parts[0].trim(); |
|
|
|
String name = parts[0].trim(); |
|
|
|
|
|
|
|
|
|
|
|
@ -136,42 +172,4 @@ public class WebSocketExtension { |
|
|
|
return new WebSocketExtension(name, parameters); |
|
|
|
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(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|