Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Benargee/bd4f791b29bddc0551ee87a99a6895cf to your computer and use it in GitHub Desktop.
Save Benargee/bd4f791b29bddc0551ee87a99a6895cf to your computer and use it in GitHub Desktop.
Super simple websockets client/server using Python. Compatible with the draft 76 challenge/response.
<!DOCTYPE html>
<html lang="en">
<head>
<title>WebSocket Client</title>
<style>
#output {
border: solid 1px #000;
}
</style>
</head>
<body>
<form id="form">
<input type="text" id="message">
<button type="submit">Send</button>
</form>
<hr>
<div id="output"></div>
<script>
var inputBox = document.getElementById("message");
var output = document.getElementById("output");
var form = document.getElementById("form");
try {
var host = "ws://" + window.location.hostname + ":9876/stuff";
console.log("Host:", host);
var s = new WebSocket(host);
s.onopen = function (e) {
console.log("Socket opened.");
};
s.onclose = function (e) {
console.log("Socket closed.");
};
s.onmessage = function (e) {
console.log("Socket message:", e.data);
var p = document.createElement("p");
p.innerHTML = e.data;
output.appendChild(p);
};
s.onerror = function (e) {
console.log("Socket error:", e);
};
} catch (ex) {
console.log("Socket exception:", ex);
}
form.addEventListener("submit", function (e) {
e.preventDefault();
s.send(inputBox.value);
inputBox.value = "";
}, false)
</script>
</body>
</html>
#!/usr/bin/env python
import socket, struct, hashlib, threading, cgi
def decode_key (key):
num = ""
spaces = 0
for c in key:
if c.isdigit():
num += c
if c.isspace():
spaces += 1
return int(num) / spaces
def create_hash (key1, key2, code):
a = struct.pack(">L", decode_key(key1))
b = struct.pack(">L", decode_key(key2))
md5 = hashlib.md5(a + b + code)
return md5.digest()
def recv_data (client, length):
data = client.recv(length)
if not data: return data
return data.decode('utf-8', 'ignore')
def send_data (client, data):
message = "\x00%s\xFF" % data.encode('utf-8')
return client.send(message)
def parse_headers (data):
headers = {}
lines = data.splitlines()
for l in lines:
parts = l.split(": ", 1)
if len(parts) == 2:
headers[parts[0]] = parts[1]
headers['code'] = lines[len(lines) - 1]
return headers
def handshake (client):
print 'Handshaking...'
data = client.recv(1024)
headers = parse_headers(data)
print 'Got headers:'
for k, v in headers.iteritems():
print k, ':', v
digest = create_hash(
headers['Sec-WebSocket-Key1'],
headers['Sec-WebSocket-Key2'],
headers['code']
)
shake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
shake += "Upgrade: WebSocket\r\n"
shake += "Connection: Upgrade\r\n"
shake += "Sec-WebSocket-Origin: %s\r\n" % (headers['Origin'])
shake += "Sec-WebSocket-Location: ws://%s/stuff\r\n" % (headers['Host'])
shake += "Sec-WebSocket-Protocol: sample\r\n\r\n"
shake += digest
return client.send(shake)
def handle (client, addr):
handshake(client)
lock = threading.Lock()
while 1:
data = recv_data(client, 1024)
if not data: break
data = cgi.escape(data)
lock.acquire()
[send_data(c, data) for c in clients]
lock.release()
print 'Client closed:', addr
lock.acquire()
clients.remove(client)
lock.release()
client.close()
def start_server ():
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 9876))
s.listen(5)
while 1:
conn, addr = s.accept()
print 'Connection from:', addr
clients.append(conn)
threading.Thread(target = handle, args = (conn, addr)).start()
clients = []
start_server()