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

Reply via email to