diff --git a/include/rfb.js b/include/rfb.js index 00fb7d88..b38ab912 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -299,7 +299,8 @@ function connect() { uri += rfb_host + ":" + rfb_port + "/" + rfb_path; } Util.Info("connecting to " + uri); - ws.open(uri); + // TODO: make protocols a configurable + ws.open(uri, ['binary', 'base64']); Util.Debug("<< RFB.connect"); } diff --git a/include/websock.js b/include/websock.js index 20d51d6a..935e3a1e 100644 --- a/include/websock.js +++ b/include/websock.js @@ -61,6 +61,7 @@ function Websock() { var api = {}, // Public API websocket = null, // WebSocket object + mode = 'base64', // Current WebSocket mode: 'binary', 'base64' rQ = [], // Receive queue rQi = 0, // Receive queue index rQmax = 10000, // Max receive queue size before compacting @@ -169,14 +170,24 @@ function rQwait(msg, num, goback) { // function encode_message() { - /* base64 encode */ - return Base64.encode(sQ); + if (mode === 'binary') { + // Put in a binary arraybuffer + return (new Uint8Array(sQ)).buffer; + } else { + // base64 encode + return Base64.encode(sQ); + } } function decode_message(data) { //Util.Debug(">> decode_message: " + data); - /* base64 decode */ - rQ = rQ.concat(Base64.decode(data, 0)); + if (mode === 'binary') { + // push arraybuffer values onto the end + rQ.push.apply(rQ, (new Uint8Array(data))); + } else { + // base64 decode and concat to the end + rQ = rQ.concat(Base64.decode(data, 0)); + } //Util.Debug(">> decode_message, rQ: " + rQ); } @@ -259,32 +270,82 @@ function on(evt, handler) { eventHandlers[evt] = handler; } -function init() { +function init(protocols) { rQ = []; rQi = 0; sQ = []; websocket = null; + + var bt = false, + wsbt = false, + try_binary = false; + + // Check for full typed array support + if (('Uint8Array' in window) && + ('set' in Uint8Array.prototype)) { + bt = true; + } + + // Check for full binary type support in WebSockets + // TODO: this sucks, the property should exist on the prototype + // but it does not. + try { + if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) { + Util.Info("Detected binaryType support in WebSockets"); + wsbt = true; + } + } catch (exc) { + // Just ignore failed test localhost connections + } + + // Default protocols if not specified + if (typeof(protocols) === "undefined") { + if (wsbt) { + protocols = ['binary', 'base64']; + } else { + protocols = 'base64'; + } + } + + // If no binary support, make sure it was not requested + if (!wsbt) { + if (protocols === 'binary') { + throw("WebSocket binary sub-protocol requested but not supported"); + } + if (typeof(protocols) === "object") { + for (var i = 0; i < protocols.length; i++) { + if (protocols[i] === 'binary') { + throw("WebSocket binary sub-protocol requested but not supported"); + } + } + } + } + + return protocols; } -function open(uri) { - init(); +function open(uri, protocols) { + protocols = init(protocols); if (test_mode) { websocket = {}; } else { - websocket = new WebSocket(uri, 'base64'); - // TODO: future native binary support - //websocket = new WebSocket(uri, ['binary', 'base64']); + websocket = new WebSocket(uri, protocols); } websocket.onmessage = recv_message; websocket.onopen = function() { Util.Debug(">> WebSock.onopen"); if (websocket.protocol) { + mode = websocket.protocol; Util.Info("Server chose sub-protocol: " + websocket.protocol); } else { + mode = 'base64'; Util.Error("Server select no sub-protocol!: " + websocket.protocol); } + if (mode === 'binary') { + websocket.binaryType = 'arraybuffer'; + } eventHandlers.open(); Util.Debug("<< WebSock.onopen"); }; diff --git a/include/webutil.js b/include/webutil.js index 6722fe38..fd153e4a 100644 --- a/include/webutil.js +++ b/include/webutil.js @@ -75,9 +75,14 @@ WebUtil.dirObj = function (obj, depth, parent) { // Read a query string variable WebUtil.getQueryVar = function(name, defVal) { - var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'); + var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'), + match = document.location.href.match(re); if (typeof defVal === 'undefined') { defVal = null; } - return (document.location.href.match(re) || ['',defVal])[1]; + if (match) { + return decodeURIComponent(match[1]); + } else { + return defVal; + } };