diff --git a/include/web-socket-js/flash-src/WebSocket.as b/include/web-socket-js/flash-src/WebSocket.as
index df254b52..03c5d8b0 100644
--- a/include/web-socket-js/flash-src/WebSocket.as
+++ b/include/web-socket-js/flash-src/WebSocket.as
@@ -219,10 +219,32 @@ public class WebSocket extends EventDispatcher {
}
} else {
if (buffer[pos] == 0xff) {
+ //if (buffer.bytesAvailable > 1) {
if (buffer.readByte() != 0x00) {
close();
main.fatal("data must start with \\x00");
}
+ /*
+ var data:String = "", byte:uint;
+ while (buffer.bytesAvailable > 1) {
+ byte = buffer[buffer.position];
+ if (byte === 0x00) {
+ // readUTFBytes mishandles 0x00
+ data = data + "\x00";
+ buffer.position++;
+ } else if (byte === 0xff) {
+ // End of WebSocket frame
+ //ExternalInterface.call("console.log", "[WebSocket] early 0xff found");
+ break;
+ } else if ((byte & 0x80) === 0x00) {
+ // One UTF-8 input byte to one output byte
+ data = data + buffer.readUTFBytes(1);
+ } else {
+ // Assume two UTF-8 input bytes to one output byte
+ data = data + buffer.readUTFBytes(2);
+ }
+ }
+ */
var data:String = buffer.readUTFBytes(pos - 1);
main.log("received: " + data);
dispatchEvent(new WebSocketMessageEvent("message", encodeURIComponent(data)));
diff --git a/include/web-socket-js/flash-src/WebSocketMain.swf b/include/web-socket-js/flash-src/WebSocketMain.swf
index 91da2f8c..c3a0ebd1 100644
Binary files a/include/web-socket-js/flash-src/WebSocketMain.swf and b/include/web-socket-js/flash-src/WebSocketMain.swf differ
diff --git a/tests/wsencoding.html b/tests/wsencoding.html
new file mode 100644
index 00000000..a783467a
--- /dev/null
+++ b/tests/wsencoding.html
@@ -0,0 +1,155 @@
+
+
+
WebSockets Test
+
+
+
+ Host:
+ Port:
+ Encrypt:
+
+
+
+ Messages:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/wsencoding.py b/tests/wsencoding.py
new file mode 100755
index 00000000..f29c2e9e
--- /dev/null
+++ b/tests/wsencoding.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+
+'''
+WebSocket server-side load test program. Sends and receives traffic
+that has a random payload (length and content) that is checksummed and
+given a sequence number. Any errors are reported and counted.
+'''
+
+import sys, os, socket, ssl, time, traceback
+import random, time
+from base64 import b64encode, b64decode
+from codecs import utf_8_encode, utf_8_decode
+from select import select
+
+sys.path.insert(0,os.path.dirname(__file__) + "/../")
+from websocket import *
+
+buffer_size = 65536
+recv_cnt = send_cnt = 0
+
+
+def check(buf):
+
+ if buf[0] != '\x00' or buf[-1] != '\xff':
+ raise Exception("Invalid WS packet")
+
+ for decoded in decode(buf):
+ nums = [ord(c) for c in decoded]
+ print "Received nums: ", nums
+
+ return
+
+
+def responder(client):
+ cpartial = ""
+ socks = [client]
+ sent = False
+ received = False
+
+ while True:
+ ins, outs, excepts = select(socks, socks, socks, 1)
+ if excepts: raise Exception("Socket exception")
+
+ if client in ins:
+ buf = client.recv(buffer_size)
+ if len(buf) == 0: raise Exception("Client closed")
+ received = True
+ #print "Client recv: %s (%d)" % (repr(buf[1:-1]), len(buf))
+ if buf[-1] == '\xff':
+ if cpartial:
+ err = check(cpartial + buf)
+ cpartial = ""
+ else:
+ err = check(buf)
+ if err:
+ print err
+ else:
+ print "received partitial"
+ cpartial = cpartial + buf
+
+ if received and not sent and client in outs:
+ sent = True
+ #nums = "".join([unichr(c) for c in range(0,256)])
+ #nums = "".join([chr(c) for c in range(1,128)])
+ #nums = nums + chr(194) + chr(128) + chr(194) + chr(129)
+ #nums = "".join([chr(c) for c in range(0,256)])
+ nums = "\x81\xff"
+ nums = nums + "".join([chr(c) for c in range(0,256,4)])
+ nums = nums + "\x00\x40\x41\xff\x81"
+# print nums
+ client.send(encode(nums))
+# client.send("\x00" + nums + "\xff")
+# print "Sent characters 0-255"
+# #print "Client send: %s (%d)" % (repr(nums), len(nums))
+
+if __name__ == '__main__':
+ try:
+ if len(sys.argv) < 2: raise
+ listen_port = int(sys.argv[1])
+ except:
+ print "Usage: "
+ sys.exit(1)
+
+ start_server(listen_port, responder)
diff --git a/vnc.js b/vnc.js
index c8a02ff4..31044f47 100644
--- a/vnc.js
+++ b/vnc.js
@@ -53,6 +53,7 @@ RFB = {
ws : null, // Web Socket object
sendID : null,
use_seq : false,
+b64encode : true,
// Receive and send queues
RQ : [], // Receive Queue
@@ -789,6 +790,27 @@ clientCutText: function (text) {
* Utility routines
*/
+encode_message: function(arr) {
+ if (RFB.b64encode) {
+ RFB.SQ = RFB.SQ + Base64.encode(arr);
+ } else {
+ RFB.SQ = RFB.SQ + arr.map(function (num) {
+ return String.fromCharCode(num); } ).join('');
+ }
+},
+
+decode_message: function(data, offset) {
+ //console.log(">> decode_message: " + data);
+ if (RFB.b64encode) {
+ RFB.RQ = RFB.RQ.concat(Base64.decode(data, offset));
+ } else {
+ RFB.RQ = RFB.RQ.concat(data.split('').slice(offset).
+ map(function (chr) {
+ return (chr.charCodeAt(0) % 256); }));
+ }
+ //console.log(">> decode_message, RQ: " + RFB.RQ);
+},
+
recv_message: function(e) {
//console.log(">> recv_message");
@@ -796,7 +818,7 @@ recv_message: function(e) {
if (RFB.use_seq) {
RFB.recv_message_reorder(e);
} else {
- RFB.RQ = RFB.RQ.concat(Base64.decode(e.data, 0));
+ RFB.decode_message(e.data, 0);
RFB.handle_message();
}
@@ -819,7 +841,7 @@ recv_message_reorder: function(e) {
offset = e.data.indexOf(":") + 1;
seq_num = parseInt(e.data.substr(0, offset-1), 10);
if (RFB.RQ_seq_num === seq_num) {
- RFB.RQ = RFB.RQ.concat(Base64.decode(e.data, offset));
+ RFB.decode_message(e.data, offset);
RFB.RQ_seq_num++;
} else {
console.warn("sequence number mismatch: expected " +
@@ -838,9 +860,7 @@ recv_message_reorder: function(e) {
/* Remove it from reorder queue, decode it and
* add it to the receive queue */
console.log("Found re-ordered packet seq_num " + seq_num);
- RFB.RQ = RFB.RQ.concat(
- Base64.decode(RFB.RQ_reorder.splice(i, 1)[0],
- offset));
+ RFB.decode_message(RFB.RQ_reorder.splice(i, 1)[0], offset);
RFB.RQ_seq_num++;
i = 0; // Start search again for next one
} else {
@@ -892,8 +912,7 @@ send_string: function (str) {
send_array: function (arr) {
//console.log(">> send_array: " + arr);
- //console.log(">> send_array: " + Base64.encode(arr));
- RFB.SQ = RFB.SQ + Base64.encode(arr);
+ RFB.encode_message(arr);
if (RFB.ws.bufferedAmount === 0) {
RFB.ws.send(RFB.SQ);
RFB.SQ = "";
@@ -1097,15 +1116,21 @@ updateState: function(state, statusMsg) {
init_ws: function () {
console.log(">> init_ws");
- var uri = "";
+ var uri = "", vars = [];
if (RFB.encrypt) {
uri = "wss://";
} else {
uri = "ws://";
}
- uri += RFB.host + ":" + RFB.port + "/?b64encode";
+ uri += RFB.host + ":" + RFB.port + "/";
+ if (RFB.b64encode) {
+ vars.push("b64encode");
+ }
if (RFB.use_seq) {
- uri += "&seq_num";
+ vars.push("seq_num");
+ }
+ if (vars.length > 0) {
+ uri += "?" + vars.join("&");
}
console.log("connecting to " + uri);
RFB.ws = new WebSocket(uri);
diff --git a/websocket.py b/websocket.py
index c7f68b44..c9b33c54 100755
--- a/websocket.py
+++ b/websocket.py
@@ -33,16 +33,26 @@ def traffic(token="."):
def decode(buf):
""" Parse out WebSocket packets. """
if buf.count('\xff') > 1:
- return [b64decode(d[1:]) for d in buf.split('\xff')]
+ if client_settings["b64encode"]:
+ return [b64decode(d[1:]) for d in buf.split('\xff')]
+ else:
+ # Modified UTF-8 decode
+ return [d[1:].replace("\xc4\x80", "\x00").decode('utf-8').encode('latin-1') for d in buf.split('\xff')]
else:
- return [b64decode(buf[1:-1])]
+ if client_settings["b64encode"]:
+ return [b64decode(buf[1:-1])]
+ else:
+ return [buf[1:-1].replace("\xc4\x80", "\x00").decode('utf-8').encode('latin-1')]
def encode(buf):
global send_seq
- if client_settings.get("b64encode"):
+ if client_settings["b64encode"]:
buf = b64encode(buf)
+ else:
+ # Modified UTF-8 encode
+ buf = buf.decode('latin-1').encode('utf-8').replace("\x00", "\xc4\x80")
- if client_settings.get("seq_num"):
+ if client_settings["seq_num"]:
send_seq += 1
return "\x00%d:%s\xff" % (send_seq-1, buf)
else:
@@ -81,7 +91,7 @@ def do_handshake(sock):
# Parse settings from the path
cvars = path.partition('?')[2].partition('#')[0].split('&')
- client_settings = {}
+ client_settings = {'b64encode': None, 'seq_num': None}
for cvar in [c for c in cvars if c]:
name, _, value = cvar.partition('=')
client_settings[name] = value and value or True