Add support for WebSocket Protocol Extensions

This commits adds simple, overridable WebSocket Extension
filtering during the handshake phase and adds that
information in the WebSocket session.

The actual WebSocket Extension negotiation happens
within the server implementation (Glassfish, Jetty, Tomcat...),
so one can only remove requested extensions from
the list provided by the WebSocket client.

See RFC6455 Section 9.

Issue: SPR-10843
This commit is contained in:
Brian Clozel
2013-10-24 11:28:21 +02:00
committed by Rossen Stoyanchev
parent 78c10cd242
commit 6d00a3f0ee
17 changed files with 441 additions and 6 deletions

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2013 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.socket;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import org.hamcrest.Matchers;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* Test fixture for {@link WebSocketExtension}
* @author Brian Clozel
*/
public class WebSocketExtensionTests {
@Test
public void parseHeaderSingle() {
List<WebSocketExtension> extensions = WebSocketExtension.parseHeader("x-test-extension ; foo=bar");
assertThat(extensions, Matchers.hasSize(1));
WebSocketExtension extension = extensions.get(0);
assertEquals("x-test-extension", extension.getName());
assertEquals(1, extension.getParameters().size());
assertEquals("bar", extension.getParameters().get("foo"));
}
@Test
public void parseHeaderMultiple() {
List<WebSocketExtension> extensions = WebSocketExtension.parseHeader("x-foo-extension, x-bar-extension");
assertThat(extensions, Matchers.hasSize(2));
assertEquals("x-foo-extension", extensions.get(0).getName());
assertEquals("x-bar-extension", extensions.get(1).getName());
}
@Test
public void parseHeaders() {
List<String> extensions = new ArrayList<String>();
extensions.add("x-foo-extension, x-bar-extension");
extensions.add("x-test-extension");
List<WebSocketExtension> parsedExtensions = WebSocketExtension.parseHeaders(extensions);
assertThat(parsedExtensions, Matchers.hasSize(3));
}
}

View File

@@ -26,6 +26,7 @@ import java.util.Map;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketExtension;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.sockjs.support.frame.SockJsFrame;
@@ -58,6 +59,8 @@ public class TestSockJsSession extends AbstractSockJsSession {
private String subProtocol;
private List<WebSocketExtension> extensions = new ArrayList<WebSocketExtension>();
public TestSockJsSession(String sessionId, SockJsServiceConfig config,
WebSocketHandler wsHandler, Map<String, Object> attributes) {
@@ -118,7 +121,7 @@ public class TestSockJsSession extends AbstractSockJsSession {
}
/**
* @param remoteAddress the remoteAddress to set
* @param localAddress the remoteAddress to set
*/
public void setLocalAddress(InetSocketAddress localAddress) {
this.localAddress = localAddress;
@@ -148,6 +151,18 @@ public class TestSockJsSession extends AbstractSockJsSession {
this.subProtocol = protocol;
}
/**
* @return the extensions
*/
@Override
public List<WebSocketExtension> getExtensions() { return this.extensions; }
/**
*
* @param extensions the extensions to set
*/
public void setExtensions(List<WebSocketExtension> extensions) { this.extensions = extensions; }
public CloseStatus getCloseStatus() {
return this.closeStatus;
}

View File

@@ -27,6 +27,7 @@ import java.util.Map;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketExtension;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
@@ -51,6 +52,8 @@ public class TestWebSocketSession implements WebSocketSession {
private String protocol;
private List<WebSocketExtension> extensions = new ArrayList<WebSocketExtension>();
private boolean open;
private final List<WebSocketMessage<?>> messages = new ArrayList<>();
@@ -149,7 +152,7 @@ public class TestWebSocketSession implements WebSocketSession {
}
/**
* @param remoteAddress the remoteAddress to set
* @param localAddress the remoteAddress to set
*/
public void setLocalAddress(InetSocketAddress localAddress) {
this.localAddress = localAddress;
@@ -184,6 +187,18 @@ public class TestWebSocketSession implements WebSocketSession {
this.protocol = protocol;
}
/**
* @return the extensions
*/
@Override
public List<WebSocketExtension> getExtensions() { return this.extensions; }
/**
*
* @param extensions the extensions to set
*/
public void setExtensions(List<WebSocketExtension> extensions) { this.extensions = extensions; }
/**
* @return the open
*/