Author: markt
Date: Thu Feb 16 23:16:40 2012
New Revision: 1245245
URL: http://svn.apache.org/viewvc?rev=1245245&view=rev
Log:
Implement sub-protocol selection
Modified:
tomcat/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java
tomcat/trunk/test/org/apache/catalina/websocket/TestWebSocket.java
tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java
tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java
Modified: tomcat/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java?rev=1245245&r1=1245244&r2=1245245&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/websocket/WebSocketServlet.java Thu
Feb 16 23:16:40 2012
@@ -19,6 +19,7 @@ package org.apache.catalina.websocket;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
@@ -68,17 +69,17 @@ public abstract class WebSocketServlet e
String subProtocol = null;
List<String> extensions = Collections.emptyList();
- if (!headerContains(req, "upgrade", "websocket")) {
+ if (!headerContainsToken(req, "upgrade", "websocket")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
- if (!headerContains(req, "connection", "upgrade")) {
+ if (!headerContainsToken(req, "connection", "upgrade")) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
- if (!headerContains(req, "sec-websocket-version", "13")) {
+ if (!headerContainsToken(req, "sec-websocket-version", "13")) {
resp.setStatus(426);
resp.setHeader("Sec-WebSocket-Version", "13");
return;
@@ -96,8 +97,14 @@ public abstract class WebSocketServlet e
return;
}
- // TODO Read client handshake - Sec-WebSocket-Protocol
- // Sec-WebSocket-Extensions
+ List<String> subProtocols = getTokensFromHeader(req,
+ "Sec-WebSocket-Protocol-Client");
+ if (!subProtocols.isEmpty()) {
+ subProtocol = selectSubProtocol(subProtocols);
+
+ }
+
+ // TODO Read client handshake - Sec-WebSocket-Extensions
// TODO Extensions require the ability to specify something (API TBD)
// that can be passed to the Tomcat internals and process
extension
@@ -108,27 +115,27 @@ public abstract class WebSocketServlet e
resp.setHeader("connection", "upgrade");
resp.setHeader("Sec-WebSocket-Accept", getWebSocketAccept(key));
if (subProtocol != null) {
- // TODO
+ resp.setHeader("Sec-WebSocket-Protocol", subProtocol);
}
if (!extensions.isEmpty()) {
// TODO
}
// Small hack until the Servlet API provides a way to do this.
- StreamInbound inbound = createWebSocketInbound();
+ StreamInbound inbound = createWebSocketInbound(subProtocol);
((RequestFacade) req).doUpgrade(inbound);
}
- private boolean headerContains(HttpServletRequest req, String headerName,
- String target) {
+ /*
+ * This only works for tokens. Quoted strings need more sophisticated
+ * parsing.
+ */
+ private boolean headerContainsToken(HttpServletRequest req,
+ String headerName, String target) {
Enumeration<String> headers = req.getHeaders(headerName);
while (headers.hasMoreElements()) {
String header = headers.nextElement();
- // TODO Splitting headers into tokens isn't quite this simple but
- // this should be OK in this case. It is tempting to change
the
- // header parsing code so there is a one to one mapping
between
- // token and enumeration entry.
String[] tokens = header.split(",");
for (String token : tokens) {
if (target.equalsIgnoreCase(token.trim())) {
@@ -140,6 +147,26 @@ public abstract class WebSocketServlet e
}
+ /*
+ * This only works for tokens. Quoted strings need more sophisticated
+ * parsing.
+ */
+ private List<String> getTokensFromHeader(HttpServletRequest req,
+ String headerName) {
+ List<String> result = new ArrayList<String>();
+
+ Enumeration<String> headers = req.getHeaders(headerName);
+ while (headers.hasMoreElements()) {
+ String header = headers.nextElement();
+ String[] tokens = header.split(",");
+ for (String token : tokens) {
+ result.add(token.trim());
+ }
+ }
+ return result;
+ }
+
+
private String getWebSocketAccept(String key) {
synchronized (sha1Helper) {
sha1Helper.reset();
@@ -163,5 +190,27 @@ public abstract class WebSocketServlet e
return true;
}
- protected abstract StreamInbound createWebSocketInbound();
+ /**
+ * Intended to be overridden by sub-classes that wish to select a
+ * sub-protocol if the client provides a list of supported protocols.
+ *
+ * @param subProtocols The list of sub-protocols supported by the client
+ * in client preference order. The server is under no
+ * obligation to respect the declared preference
+ * @return <code>null</code> if no sub-protocol is selected or the name of
+ * the protocol which <b>must</b> be one of the protocols listed
by
+ * the client.
+ */
+ protected String selectSubProtocol(List<String> subProtocols) {
+ return null;
+ }
+
+ /**
+ * Create the instance that will process this inbound connection.
+ *
+ * @param subProtocol The sub-protocol agreed between the client and
+ * server or <code>null</code> if none was agreed
+ * @return
+ */
+ protected abstract StreamInbound createWebSocketInbound(String
subProtocol);
}
Modified: tomcat/trunk/test/org/apache/catalina/websocket/TestWebSocket.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/websocket/TestWebSocket.java?rev=1245245&r1=1245244&r2=1245245&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/websocket/TestWebSocket.java
(original)
+++ tomcat/trunk/test/org/apache/catalina/websocket/TestWebSocket.java Thu Feb
16 23:16:40 2012
@@ -38,7 +38,7 @@ public class TestWebSocket extends Tomca
private static final long serialVersionUID = 1L;
@Override
- protected StreamInbound createWebSocketInbound() {
+ protected StreamInbound createWebSocketInbound(String subProtocol) {
return new SimpleStreamInbound();
}
}
@@ -63,7 +63,7 @@ public class TestWebSocket extends Tomca
private static final long serialVersionUID = 1L;
@Override
- protected StreamInbound createWebSocketInbound() {
+ protected StreamInbound createWebSocketInbound(String subProtocol) {
return new SimpleMessageInbound();
}
}
Modified:
tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java?rev=1245245&r1=1245244&r2=1245245&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java
(original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoMessage.java
Thu Feb 16 23:16:40 2012
@@ -30,7 +30,7 @@ public class EchoMessage extends WebSock
private static final long serialVersionUID = 1L;
@Override
- protected StreamInbound createWebSocketInbound() {
+ protected StreamInbound createWebSocketInbound(String subProtocol) {
return new EchoMessageInbound();
}
Modified:
tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java?rev=1245245&r1=1245244&r2=1245245&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java
(original)
+++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/EchoStream.java Thu
Feb 16 23:16:40 2012
@@ -30,7 +30,7 @@ public class EchoStream extends WebSocke
private static final long serialVersionUID = 1L;
@Override
- protected StreamInbound createWebSocketInbound() {
+ protected StreamInbound createWebSocketInbound(String subProtocol) {
return new EchoStreamInbound();
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]