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: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org