Trying to create a web interface for an application running Python3. The application will require bidirectional streaming, which sounds like a good opportunity to peek at websites.
My first wish was to use something already existing, and the sample applications from mod-pywebsocket proved to be valuable. Unfortunately, their APIs seem to be easily extensible, and that is Python2.
Looking back at the blogosphere, many people wrote their own websocket server for earlier versions of the websocket protocol, most of them do not implement hashing the security key, so they do not work.
Reading RFC 6455 I decided to take a hit at it myself and came up with the following:
#!/usr/bin/env python3 """ A partial implementation of RFC 6455 http://tools.ietf.org/pdf/rfc6455.pdf Brian Thorne 2012 """ import socket import threading import time import base64 import hashlib def calculate_websocket_hash(key): magic_websocket_string = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" result_string = key + magic_websocket_string sha1_digest = hashlib.sha1(result_string).digest() response_data = base64.encodestring(sha1_digest) response_string = response_data.decode('utf8') return response_string def is_bit_set(int_type, offset): mask = 1 << offset return not 0 == (int_type & mask) def set_bit(int_type, offset): return int_type | (1 << offset) def bytes_to_int(data):
Using this basic test page (which works with mod-pywebsocket):
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Web Socket Example</title> <meta charset="UTF-8"> </head> <body> <div id="serveroutput"></div> <form id="form"> <input type="text" value="Hello World!" id="msg" /> <input type="submit" value="Send" onclick="sendMsg()" /> </form> <script> var form = document.getElementById('form'); var msg = document.getElementById('msg'); var output = document.getElementById('serveroutput'); var s = new WebSocket("ws://"+window.location.hostname+":9876"); s.onopen = function(e) { console.log("opened"); out('Connected.'); } s.onclose = function(e) { console.log("closed"); out('Connection closed.'); } s.onmessage = function(e) { console.log("got: " + e.data); out(e.data); } form.onsubmit = function(e) { e.preventDefault(); msg.value = ''; window.scrollTop = window.scrollHeight; } function sendMsg() { s.send(msg.value); } function out(text) { var el = document.createElement('p'); el.innerHTML = text; output.appendChild(el); } msg.focus(); </script> </body> </html>
This receives the data and clears it correctly, but I cannot get the transmission traffic to work.
As a test for writing "Hello" to a socket, the program above calculates the bytes that should be written to the socket, like:
['0x81', '0x5', '0x48', '0x65', '0x6c', '0x6c', '0x6f']
Which correspond to the hexadecimal values โโgiven in Section 5.7 of the RFC. Unfortunately, the frame never appears in Chrome Developer Tools.
Any idea what I am missing? Or the current working Python3 web layout example?