Anonymous avatar Anonymous committed ab11fd2

Complete server's opening handshake

Comments (0)

Files changed (5)

 syntax: glob
 
-.pyc
+*.pyc
+*.sw?
+gevent_websocket.egg-info/*
 tests/testresults.sqlite3

geventwebsocket/__init__.py

 
 try:
     from geventwebsocket.websocket import WebSocket
+    from geventwebsocket.websocket import WebSocketVersion7
 except ImportError:
     import traceback
     traceback.print_exc()

geventwebsocket/handler.py

 import base64
 import re
 import struct
-from hashlib import md5
+from hashlib import md5, sha1
 
 from gevent.pywsgi import WSGIHandler
-from geventwebsocket import WebSocket
+from geventwebsocket import WebSocket, WebSocketVersion7
 
 
 class HandShakeError(ValueError):
 
 
 class WebSocketHandler(WSGIHandler):
+    GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+
     """ Automatically upgrades the connection to websockets. """
     def __init__(self, *args, **kwargs):
         self.websocket_connection = False
         environ = self.environ
 
         protocol, version = self.request_version.split("/")
+        key = environ.get("HTTP_SEC_WEBSOCKET_KEY")
+
         # check client handshake for validity
         if not environ.get("REQUEST_METHOD") == "GET":
             # 5.2.1 (1)
             # 5.2.1 (2)
             self._close_connection()
             return False
-        elif not environ.get("HTTP_SEC_WEBSOCKET_KEY"):
+        elif not key:
             # 5.2.1 (3)
             self._close_connection()
             return False
-        elif len(base64.b64decode(environ.get("HTTP_SEC_WEBSOCKET_KEY"))) != 16:
+        elif len(base64.b64decode(key)) != 16:
             # 5.2.1 (3)
             self._close_connection()
             return False
-        #TODO: provide a way to specify how to handle Sec-WebSocket-Origin if present
+
+        #TODO: compare Sec-WebSocket-Origin against self.allowed_paths
+
+        self.websocket_connection = True
+        self.websocket = WebSocketVersion7(self.socket, self.rfile, self.environ)
+        self.environ['wsgi.websocket'] = self.websocket
+
+        headers = [
+            ("Upgrade", "websocket"),
+            ("Connection", "Upgrade"),
+            ("Sec-WebSocket-Accept", base64.b64encode(sha1(key + self.GUID).digest())),
+        ]
+        self.start_response("101 Switching Protocols", headers)
+        return True
 
     def _handle_one_legacy_response(self):
         # In case the client doesn't want to initialize a WebSocket connection

geventwebsocket/websocket.py

                         self.rfile.read(length) # discard the bytes
             else:
                 raise IOError("Reveiced an invalid message")
+
+class WebSocketVersion7(WebSocket):
+    def __init__(self, sock, rfile, environ):
+        self.rfile = rfile
+        self.socket = sock
+        self.origin = environ.get('HTTP_SEC_WEBSOCKET_ORIGIN')
+        self.protocol = environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL', 'unknown')
+        self.path = environ.get('PATH_INFO')
+        self.websocket_closed = False

tests/test__websocket.py

         return socket.create_connection(('127.0.0.1', self.port))
 
 
-"""
 class TestWebSocket(TestCase):
     message = "\x00Hello world\xff"
 
                'Unexpected message: %r (expected %r)\n%s' % (message, self.message, self)
 
         fd.close()
-"""
 
 class TestWebSocketVersion7(TestCase):
     def application(self, environ, start_response):
             try:
                 ws = environ['wsgi.websocket']
             except KeyError:
-                print ">>> In TestWebSocketVersion7.application!\n\n"
                 start_response("400 Bad Request", [])
                 return []
 
         assert closed, "Failed to abort connection with key that is too long"
         fd.close()
 
+    def test_good_handshake(self):
+        fd = self.connect().makefile(bufsize=1)
+        headers = "" \
+            "GET /echo HTTP/1.1\r\n" \
+            "Host: localhost\r\n" \
+            "Upgrade: WebSocket\r\n" \
+            "Connection: Upgrade\r\n" \
+            "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" \
+            "Sec-WebSocket-Origin: http://localhost\r\n" \
+            "Sec-WebSocket-Protocol: chat, superchat\r\n" \
+            "Sec-WebSocket-Version: 7\r\n" \
+            "\r\n"
+
+        fd.write(headers)
+        response = read_http(fd, code=101, reason="Switching Protocols")
+        response.assertHeader("Upgrade", "websocket")
+        response.assertHeader("Connection", "Upgrade")
+        response.assertHeader("Sec-WebSocket-Accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
+
+        fd.close();
+
+
     """
     def test_handshake(self):
         fd = self.connect().makefile(bufsize=1)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.