Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Complete server's opening handshake

--HG--
branch : stable
  • Loading branch information...
commit 5b17f661f3e58a2db19d7a9ca8215c3d67dfc75e 1 parent b1401eb
Lon Ingram authored
4 .hgignore
... ... @@ -1,4 +1,6 @@
1 1 syntax: glob
2 2
3   -.pyc
  3 +*.pyc
  4 +*.sw?
  5 +gevent_websocket.egg-info/*
4 6 tests/testresults.sqlite3
1  geventwebsocket/__init__.py
@@ -4,6 +4,7 @@
4 4
5 5 try:
6 6 from geventwebsocket.websocket import WebSocket
  7 + from geventwebsocket.websocket import WebSocketVersion7
7 8 except ImportError:
8 9 import traceback
9 10 traceback.print_exc()
27 geventwebsocket/handler.py
... ... @@ -1,10 +1,10 @@
1 1 import base64
2 2 import re
3 3 import struct
4   -from hashlib import md5
  4 +from hashlib import md5, sha1
5 5
6 6 from gevent.pywsgi import WSGIHandler
7   -from geventwebsocket import WebSocket
  7 +from geventwebsocket import WebSocket, WebSocketVersion7
8 8
9 9
10 10 class HandShakeError(ValueError):
@@ -13,6 +13,8 @@ class HandShakeError(ValueError):
13 13
14 14
15 15 class WebSocketHandler(WSGIHandler):
  16 + GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
  17 +
16 18 """ Automatically upgrades the connection to websockets. """
17 19 def __init__(self, *args, **kwargs):
18 20 self.websocket_connection = False
@@ -62,6 +64,8 @@ def _handle_one_version7_response(self):
62 64 environ = self.environ
63 65
64 66 protocol, version = self.request_version.split("/")
  67 + key = environ.get("HTTP_SEC_WEBSOCKET_KEY")
  68 +
65 69 # check client handshake for validity
66 70 if not environ.get("REQUEST_METHOD") == "GET":
67 71 # 5.2.1 (1)
@@ -79,15 +83,28 @@ def _handle_one_version7_response(self):
79 83 # 5.2.1 (2)
80 84 self._close_connection()
81 85 return False
82   - elif not environ.get("HTTP_SEC_WEBSOCKET_KEY"):
  86 + elif not key:
83 87 # 5.2.1 (3)
84 88 self._close_connection()
85 89 return False
86   - elif len(base64.b64decode(environ.get("HTTP_SEC_WEBSOCKET_KEY"))) != 16:
  90 + elif len(base64.b64decode(key)) != 16:
87 91 # 5.2.1 (3)
88 92 self._close_connection()
89 93 return False
90   - #TODO: provide a way to specify how to handle Sec-WebSocket-Origin if present
  94 +
  95 + #TODO: compare Sec-WebSocket-Origin against self.allowed_paths
  96 +
  97 + self.websocket_connection = True
  98 + self.websocket = WebSocketVersion7(self.socket, self.rfile, self.environ)
  99 + self.environ['wsgi.websocket'] = self.websocket
  100 +
  101 + headers = [
  102 + ("Upgrade", "websocket"),
  103 + ("Connection", "Upgrade"),
  104 + ("Sec-WebSocket-Accept", base64.b64encode(sha1(key + self.GUID).digest())),
  105 + ]
  106 + self.start_response("101 Switching Protocols", headers)
  107 + return True
91 108
92 109 def _handle_one_legacy_response(self):
93 110 # In case the client doesn't want to initialize a WebSocket connection
9 geventwebsocket/websocket.py
@@ -97,3 +97,12 @@ def wait(self):
97 97 self.rfile.read(length) # discard the bytes
98 98 else:
99 99 raise IOError("Reveiced an invalid message")
  100 +
  101 +class WebSocketVersion7(WebSocket):
  102 + def __init__(self, sock, rfile, environ):
  103 + self.rfile = rfile
  104 + self.socket = sock
  105 + self.origin = environ.get('HTTP_SEC_WEBSOCKET_ORIGIN')
  106 + self.protocol = environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL', 'unknown')
  107 + self.path = environ.get('PATH_INFO')
  108 + self.websocket_closed = False
25 tests/test__websocket.py
@@ -225,7 +225,6 @@ def connect(self):
225 225 return socket.create_connection(('127.0.0.1', self.port))
226 226
227 227
228   -"""
229 228 class TestWebSocket(TestCase):
230 229 message = "\x00Hello world\xff"
231 230
@@ -351,7 +350,6 @@ def test_protocol_version75(self):
351 350 'Unexpected message: %r (expected %r)\n%s' % (message, self.message, self)
352 351
353 352 fd.close()
354   -"""
355 353
356 354 class TestWebSocketVersion7(TestCase):
357 355 def application(self, environ, start_response):
@@ -359,7 +357,6 @@ def application(self, environ, start_response):
359 357 try:
360 358 ws = environ['wsgi.websocket']
361 359 except KeyError:
362   - print ">>> In TestWebSocketVersion7.application!\n\n"
363 360 start_response("400 Bad Request", [])
364 361 return []
365 362
@@ -508,6 +505,28 @@ def test_bad_handshake_long_key(self):
508 505 assert closed, "Failed to abort connection with key that is too long"
509 506 fd.close()
510 507
  508 + def test_good_handshake(self):
  509 + fd = self.connect().makefile(bufsize=1)
  510 + headers = "" \
  511 + "GET /echo HTTP/1.1\r\n" \
  512 + "Host: localhost\r\n" \
  513 + "Upgrade: WebSocket\r\n" \
  514 + "Connection: Upgrade\r\n" \
  515 + "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n" \
  516 + "Sec-WebSocket-Origin: http://localhost\r\n" \
  517 + "Sec-WebSocket-Protocol: chat, superchat\r\n" \
  518 + "Sec-WebSocket-Version: 7\r\n" \
  519 + "\r\n"
  520 +
  521 + fd.write(headers)
  522 + response = read_http(fd, code=101, reason="Switching Protocols")
  523 + response.assertHeader("Upgrade", "websocket")
  524 + response.assertHeader("Connection", "Upgrade")
  525 + response.assertHeader("Sec-WebSocket-Accept", "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
  526 +
  527 + fd.close();
  528 +
  529 +
511 530 """
512 531 def test_handshake(self):
513 532 fd = self.connect().makefile(bufsize=1)

0 comments on commit 5b17f66

Please sign in to comment.
Something went wrong with that request. Please try again.