commit 05a8c895644ab098f7118c326c5904a6e9a217b6 Author: David Fifield david@bamsoftware.com Date: Wed Mar 28 01:20:27 2012 -0700
Add WebSocketBinaryDecoder and WebSocketBinaryEncoder. --- connector.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/connector.py b/connector.py index 2a06523..4077f69 100755 --- a/connector.py +++ b/connector.py @@ -1,5 +1,6 @@ #!/usr/bin/env python
+import base64 import getopt import httplib import os @@ -315,6 +316,51 @@ class WebSocketEncoder(object): payload = payload.encode("utf-8") return self.encode_frame(opcode, payload)
+# WebSocket implementations generally support text (opcode 1) messages, which +# are UTF-8-encoded text. Not all support binary (opcode 2) messages. During the +# WebSocket handshake, we use the "base64" value of the Sec-WebSocket-Protocol +# header field to indicate that text frames should encoded UTF-8-encoded +# base64-encoded binary data. Binary messages are always interpreted verbatim, +# but text messages are rejected if "base64" was not negotiated. +# +# The idea here is that browsers that know they don't support binary messages +# can negotiate "base64" with both endpoints and still reliably transport binary +# data. Those that know they can support binary messages can just use binary +# messages in the straightforward way. + +class WebSocketBinaryDecoder(object): + def __init__(self, protocols, use_mask = False): + self.dec = WebSocketDecoder(use_mask) + self.base64 = "base64" in protocols + + def feed(self, data): + self.dec.feed(data) + + def read(self): + while True: + message = self.dec.read_message() + if message is None: + return None + elif message.opcode == 1: + if not self.base64: + raise ValueError("Received text message on decoder incapable of base64") + return base64.b64decode(message.payload) + elif message.opcode == 2: + return message.payload + # Ignore all other opcodes. + return None + +class WebSocketBinaryEncoder(object): + def __init__(self, protocols, use_mask = False): + self.enc = WebSocketEncoder(use_mask) + self.base64 = "base64" in protocols + + def encode(self, data): + if self.base64: + return self.enc.encode_message(1, base64.b64encode(data)) + else: + return self.enc.encode_message(2, data) +
def listen_socket(addr): """Return a nonblocking socket listening on the given address."""
tor-commits@lists.torproject.org