summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorliris <liris.pp@gmail.com>2012-01-10 09:19:31 +0900
committerliris <liris.pp@gmail.com>2012-01-10 09:19:31 +0900
commit295a364532ceba3ca9c4f2ef8aad98e1d8efd304 (patch)
treeebb625cbf8a7fc117ab04c5f25a8faee7b03021c
parent0b8c7e0aac5a707cb9ae0f5acfaddfde02c7b9fa (diff)
downloadwebsocket-client-295a364532ceba3ca9c4f2ef8aad98e1d8efd304.tar.gz
- handshake is workable.
-rw-r--r--data/header01.txt5
-rw-r--r--data/header02.txt5
-rw-r--r--setup.py2
-rw-r--r--test_websocket.py54
-rw-r--r--websocket.py116
5 files changed, 54 insertions, 128 deletions
diff --git a/data/header01.txt b/data/header01.txt
index f177596..3142b43 100644
--- a/data/header01.txt
+++ b/data/header01.txt
@@ -1,9 +1,6 @@
HTTP/1.1 101 WebSocket Protocol Handshake
Connection: Upgrade
Upgrade: WebSocket
-sec-websocket-location: http://localhost/r
-sec-websocket-origin: http://localhost/r
+Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0=
some_header: something
-ssssss
-aaaaaaaa
diff --git a/data/header02.txt b/data/header02.txt
index c28f20f..a9dd2ce 100644
--- a/data/header02.txt
+++ b/data/header02.txt
@@ -1,9 +1,6 @@
HTTP/1.1 101 WebSocket Protocol Handshake
Connection: Upgrade
Upgrade WebSocket
-sec-websocket-location: http://localhost/r
-sec-websocket-origin: http://localhost/r
+Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0=
some_header: something
-ssssss
-aaaaaaaa
diff --git a/setup.py b/setup.py
index f05cb21..edb2a8b 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
from setuptools import setup
-VERSION = "0.4.1"
+VERSION = "0.5.0"
setup(
diff --git a/test_websocket.py b/test_websocket.py
index 26e5ff3..2d65c63 100644
--- a/test_websocket.py
+++ b/test_websocket.py
@@ -92,50 +92,39 @@ class WebSocketTest(unittest.TestCase):
self.assertRaises(ValueError, ws._parse_url, "http://www.example.com/r")
def testWSKey(self):
- n, k = ws._create_sec_websocket_key()
- self.assert_(0 < n < (1<<32))
- self.assert_(len(k) > 0)
-
- k3 = ws._create_key3()
- self.assertEquals(len(k3), 8)
+ key = ws._create_sec_websocket_key()
+ self.assert_(key != 24)
+ self.assert_("¥n" not in key)
def testWsUtils(self):
sock = ws.WebSocket()
- self.assertNotEquals(sock._validate_resp(1,2,"test", "fuga"), True)
- hashed = '6\xa3p\xb6#\xac\xb9=\xec\x0e\x96\xb5\xc1@\x1d\x90'
- self.assertEquals(sock._validate_resp(1,2,"test", hashed), True)
- hibi_header = {
+ key = "c6b8hTg4EeGb2gQMztV1/g=="
+ required_header = {
"upgrade": "websocket",
"connection": "upgrade",
- "sec-websocket-origin": "http://www.example.com",
- "sec-websocket-location": "http://www.example.com",
+ "sec-websocket-accept": "Kxep+hNu9n51529fGidYu7a3wO0=",
}
- self.assertEquals(sock._validate_header(hibi_header), (True, True))
+ self.assertEquals(sock._validate_header(required_header, key), True)
- header = hibi_header.copy()
+ header = required_header.copy()
header["upgrade"] = "http"
- self.assertEquals(sock._validate_header(header), (False, False))
+ self.assertEquals(sock._validate_header(header, key), False)
del header["upgrade"]
- self.assertEquals(sock._validate_header(header), (False, False))
-
- header = hibi_header.copy()
- header["connection"] = "http"
- self.assertEquals(sock._validate_header(header), (False, False))
+ self.assertEquals(sock._validate_header(header, key), False)
+
+ header = required_header.copy()
+ header["connection"] = "something"
+ self.assertEquals(sock._validate_header(header, key), False)
del header["connection"]
- self.assertEquals(sock._validate_header(header), (False, False))
+ self.assertEquals(sock._validate_header(header, key), False)
- header = hibi_header.copy()
- header["sec-websocket-origin"] = "somewhere origin"
- self.assertEquals(sock._validate_header(header), (True, True))
- del header["sec-websocket-origin"]
- self.assertEquals(sock._validate_header(header), (False, True))
- header = hibi_header.copy()
- header["sec-websocket-location"] = "somewhere location"
- self.assertEquals(sock._validate_header(header), (True, True))
- del header["sec-websocket-location"]
- self.assertEquals(sock._validate_header(header), (False, True))
+ header = required_header.copy()
+ header["sec-websocket-accept"] = "something"
+ self.assertEquals(sock._validate_header(header, key), False)
+ del header["sec-websocket-accept"]
+ self.assertEquals(sock._validate_header(header, key), False)
def testReadHeader(self):
sock = ws.WebSocket()
@@ -143,10 +132,7 @@ class WebSocketTest(unittest.TestCase):
status, header = sock._read_headers()
self.assertEquals(status, 101)
self.assertEquals(header["connection"], "upgrade")
- self.assertEquals("ssssss" in header, False)
- self.assertEquals(sock._get_resp(), "ssssss\r\naaaaaaaa")
-
sock.io_sock = sock.sock = HeaderSockMock("data/header02.txt")
self.assertRaises(ws.WebSocketException, sock._read_headers)
diff --git a/websocket.py b/websocket.py
index 0b95c85..8c5078a 100644
--- a/websocket.py
+++ b/websocket.py
@@ -22,12 +22,14 @@ Copyright (C) 2010 Hiroki Ohtani(liris)
import socket
from urlparse import urlparse
-import random
-import struct
-import hashlib
+import uuid
+import sha
+import base64
import logging
+VERSION = 13
+
logger = logging.getLogger()
class WebSocketException(Exception):
@@ -128,39 +130,14 @@ _MAX_CHAR_BYTE = (1<<8) -1
# http://axod.blogspot.com/2010/06/websocket-gets-update-and-it-breaks.html
def _create_sec_websocket_key():
- spaces_n = random.randint(1, 12)
- max_n = _MAX_INTEGER / spaces_n
- number_n = random.randint(0, max_n)
- product_n = number_n * spaces_n
- key_n = str(product_n)
- for i in range(random.randint(1, 12)):
- c = random.choice(_AVAILABLE_KEY_CHARS)
- pos = random.randint(0, len(key_n))
- key_n = key_n[0:pos] + chr(c) + key_n[pos:]
- for i in range(spaces_n):
- pos = random.randint(1, len(key_n)-1)
- key_n = key_n[0:pos] + " " + key_n[pos:]
-
- return number_n, key_n
-
-def _create_key3():
- return "".join([chr(random.randint(0, _MAX_CHAR_BYTE)) for i in range(8)])
+ uid = uuid.uuid1()
+ return base64.encodestring(uid.bytes).strip()
HEADERS_TO_CHECK = {
"upgrade": "websocket",
"connection": "upgrade",
}
-HEADERS_TO_EXIST_FOR_HYBI00 = [
- "sec-websocket-origin",
- "sec-websocket-location",
-]
-
-HEADERS_TO_EXIST_FOR_HIXIE75 = [
- "websocket-origin",
- "websocket-location",
-]
-
class _SSLSocketWrapper(object):
def __init__(self, sock):
self.ssl = socket.ssl(sock)
@@ -229,7 +206,7 @@ class WebSocket(object):
sock = self.io_sock
headers = []
headers.append("GET %s HTTP/1.1" % resource)
- headers.append("Upgrade: WebSocket")
+ headers.append("Upgrade: websocket")
headers.append("Connection: Upgrade")
if port == 80:
hostport = host
@@ -238,16 +215,15 @@ class WebSocket(object):
headers.append("Host: %s" % hostport)
headers.append("Origin: %s" % hostport)
- number_1, key_1 = _create_sec_websocket_key()
- headers.append("Sec-WebSocket-Key1: %s" % key_1)
- number_2, key_2 = _create_sec_websocket_key()
- headers.append("Sec-WebSocket-Key2: %s" % key_2)
+ key = _create_sec_websocket_key()
+ headers.append("Sec-WebSocket-Key: %s" % key)
+ headers.append("Sec-WebSocket-Protocol: chat, superchat")
+ headers.append("Sec-WebSocket-Version: %s" % VERSION)
if "header" in options:
headers.extend(options["header"])
headers.append("")
- key3 = _create_key3()
- headers.append(key3)
+ headers.append("")
header_str = "\r\n".join(headers)
sock.send(header_str)
@@ -260,61 +236,31 @@ class WebSocket(object):
if status != 101:
self.close()
raise WebSocketException("Handshake Status %d" % status)
- success, secure = self._validate_header(resp_headers)
+
+ success = self._validate_header(resp_headers, key)
if not success:
self.close()
raise WebSocketException("Invalid WebSocket Header")
- if secure:
- resp = self._get_resp()
- if not self._validate_resp(number_1, number_2, key3, resp):
- self.close()
- raise WebSocketException("challenge-response error")
-
self.connected = True
- def _validate_resp(self, number_1, number_2, key3, resp):
- challenge = struct.pack("!I", number_1)
- challenge += struct.pack("!I", number_2)
- challenge += key3
- digest = hashlib.md5(challenge).digest()
-
- return resp == digest
-
- def _get_resp(self):
- result = self._recv(16)
- if traceEnabled:
- logger.debug("--- challenge response result ---")
- logger.debug(repr(result))
- logger.debug("---------------------------------")
+ def _validate_header(self, headers, key):
+ for k, v in HEADERS_TO_CHECK.iteritems():
+ r = headers.get(k, None)
+ if not r:
+ return False
+ r = r.lower()
+ if v != r:
+ return False
+
+ result = headers.get("sec-websocket-accept", None)
+ if not result:
+ return False
+ result = result.lower()
- return result
-
- def _validate_header(self, headers):
- #TODO: check other headers
- for key, value in HEADERS_TO_CHECK.iteritems():
- v = headers.get(key, None)
- if value != v:
- return False, False
-
- success = 0
- for key in HEADERS_TO_EXIST_FOR_HYBI00:
- if key in headers:
- success += 1
- if success == len(HEADERS_TO_EXIST_FOR_HYBI00):
- return True, True
- elif success != 0:
- return False, True
-
- success = 0
- for key in HEADERS_TO_EXIST_FOR_HIXIE75:
- if key in headers:
- success += 1
- if success == len(HEADERS_TO_EXIST_FOR_HIXIE75):
- return True, False
-
- return False, False
-
+ value = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+ hashed = base64.encodestring(sha.sha(value).digest()).strip().lower()
+ return hashed == result
def _read_headers(self):
status = None