Skip to content

Instantly share code, notes, and snippets.

@lostcoaster
Forked from jkp/websocketserver.py
Last active August 29, 2015 14:03
Show Gist options
  • Save lostcoaster/3c5e287e7a6e151acde5 to your computer and use it in GitHub Desktop.
Save lostcoaster/3c5e287e7a6e151acde5 to your computer and use it in GitHub Desktop.
Make it compatible with python 3.4
#!python 3
import struct
import socketserver
from base64 import b64encode
from hashlib import sha1
import email
class WebSocketsHandler(socketserver.StreamRequestHandler):
magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
debug = False
def __init__(self, request, client_address, server):
self.handshake_done = False
super().__init__(request, client_address, server)
def setup(self):
socketserver.StreamRequestHandler.setup(self)
if self.debug:
print("connection established", self.client_address)
def handle(self):
while True:
if not self.handshake_done:
self.handshake()
else:
self.read_next_message()
def read_next_message(self):
length = self.rfile.read(2)[1] & 127 # rfile in rb mode
if length == 126:
length = struct.unpack(">H", self.rfile.read(2).decode('utf-8'))[0]
elif length == 127:
length = struct.unpack(">Q", self.rfile.read(8).decode('utf-8'))[0]
masks = [byte for byte in self.rfile.read(4)]
decoded = ""
for char in self.rfile.read(length):
decoded += chr(char ^ masks[len(decoded) % 4])
self.on_message(decoded)
def send_message(self, message):
self.request.send(chr(129))
length = len(message)
if length <= 125:
self.request.send(chr(length))
elif 126 <= length <= 65535:
self.request.send(126)
self.request.send(struct.pack(">H", length))
else:
self.request.send(127)
self.request.send(struct.pack(">Q", length))
self.request.send(message)
def handshake(self):
data = self.request.recv(1024).strip()
headers = email.message_from_string(data.decode('UTF-8').split('\r\n', 1)[1])
if headers.get("Upgrade", None) != "websocket":
return
if self.debug:
print('Handshaking...')
key = headers['Sec-WebSocket-Key']
digest = b64encode(sha1((key + self.magic).encode('UTF-8')).digest()).decode('UTF-8')
response = 'HTTP/1.1 101 Switching Protocols\r\n'
response += 'Upgrade: websocket\r\n'
response += 'Connection: Upgrade\r\n'
response += 'Sec-WebSocket-Accept: %s\r\n\r\n' % digest
self.handshake_done = self.request.send(response.encode('UTF-8'))
def on_message(self, message):
print(message)
if __name__ == "__main__":
server = SocketServer.TCPServer(
("localhost", 9999), WebSocketsHandler)
server.serve_forever()
@omcdr
Copy link

omcdr commented Aug 27, 2014

Hi

In function send_message tested on Python 3.3 I got error:

self.request.send(chr(129))
TypeError: 'str' does not support the buffer interface

I have added bytes with utf-8 encoding:

    def send_message(self, message):
        self.request.send(bytes(chr(129), 'utf-8'))     
        length = len(message)
        if length <= 125:
            self.request.send(bytes(chr(length),'utf-8'))
        elif 126 <= length <= 65535:
            self.request.send(126)
            self.request.send(struct.pack(">H", length))
        else:
            self.request.send(127)
            self.request.send(struct.pack(">Q", length))
        self.request.send(bytes(message, 'utf-8'))

But in function on_message like this:

    def on_message(self, message):
        print(message)
        if message == 'ping':
            self.send_message("ping reply\r\n\")

I got error:

  File "C:\tmp\py\server\my_server\TWebsocketHandler.py", line 36, in handle
    self.read_next_message()
  File "C:\tmp\py\server\my_server\TWebsocketHandler.py", line 42, in read_next_message
    length = self.rfile.read(2)[1] & 127  # rfile in rb mode
IndexError: index out of range

Do you have idea how to correct this ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment