]> git.proxmox.com Git - mirror_novnc.git/blobdiff - include/websock.js
Pull in latest websockify.
[mirror_novnc.git] / include / websock.js
index 20d51d6a2d0b5f929691252b2114bd38ea833ce3..e3f9d2af39c46ed5d88e28197af2df2351f8bb7d 100644 (file)
@@ -61,6 +61,8 @@ function Websock() {
 
 var api = {},         // Public API
     websocket = null, // WebSocket object
+    protocols,        // Protocols to request in priority order
+    mode = 'base64',
     rQ = [],          // Receive queue
     rQi = 0,          // Receive queue index
     rQmax = 10000,    // Max receive queue size before compacting
@@ -123,26 +125,46 @@ function rQshift32() {
            (rQ[rQi++] <<  8) +
            (rQ[rQi++]      );
 }
+function rQslice(start, end) {
+    if (mode === 'binary') {
+        if (end) {
+            return rQ.subarray(rQi + start, rQi + end);
+        } else {
+            return rQ.subarray(rQi + start);
+        }
+    } else {
+        if (end) {
+            return rQ.slice(rQi + start, rQi + end);
+        } else {
+            return rQ.slice(rQi + start);
+        }
+    }
+}
+
 function rQshiftStr(len) {
     if (typeof(len) === 'undefined') { len = rQlen(); }
-    var arr = rQ.slice(rQi, rQi + len);
+    var arr = rQslice(0, len);
     rQi += len;
-    return arr.map(function (num) {
-            return String.fromCharCode(num); } ).join('');
-
+    return String.fromCharCode.apply(null, arr);
 }
 function rQshiftBytes(len) {
     if (typeof(len) === 'undefined') { len = rQlen(); }
-    rQi += len;
-    return rQ.slice(rQi-len, rQi);
-}
-
-function rQslice(start, end) {
-    if (end) {
-        return rQ.slice(rQi + start, rQi + end);
+    var a = rQslice(0, len), b = [];
+    if (mode === 'binary') {
+        // Convert to plain array
+        b.push.apply(b, a);
     } else {
-        return rQ.slice(rQi + start);
+        // Already plain array, just return the original
+        b = a
     }
+    rQi += len;
+    return b;
+}
+function rQshiftArray(len) {
+    if (typeof(len) === 'undefined') { len = rQlen(); }
+    var a = rQslice(0, len);
+    rQi += len;
+    return a;
 }
 
 // Check to see if we must wait for 'num' bytes (default to FBU.bytes)
@@ -170,13 +192,26 @@ function rQwait(msg, num, goback) {
 
 function encode_message() {
     /* base64 encode */
-    return Base64.encode(sQ);
+    if (mode === 'binary') {
+        return (new Uint8Array(sQ)).buffer;
+    } else {
+        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') {
+        // Create new arraybuffer and dump old and new data into it 
+        // TODO: this could be far more efficient and re-use the array
+        var new_rQ = new Uint8Array(rQ.length + data.byteLength);
+        new_rQ.set(rQ);
+        new_rQ.set(new Uint8Array(data), rQ.length);
+        rQ = new_rQ;
+    } else {
+        /* base64 decode and concat to the end */
+        rQ = rQ.concat(Base64.decode(data, 0));
+    }
     //Util.Debug(">> decode_message, rQ: " + rQ);
 }
 
@@ -230,7 +265,7 @@ function recv_message(e) {
             // Compact the receive queue
             if (rQ.length > rQmax) {
                 //Util.Debug("Compacting receive queue");
-                rQ = rQ.slice(rQi);
+                rQ = rQslice(rQi);
                 rQi = 0;
             }
         } else {
@@ -263,7 +298,32 @@ function init() {
     rQ         = [];
     rQi        = 0;
     sQ         = [];
-    websocket  = null;
+    websocket  = null,
+    protocols  = "base64";
+
+    var bt = false,
+        wsbt = false;
+
+    if (('Uint8Array' in window) &&
+        ('set' in Uint8Array.prototype)) {
+        bt = true;
+    }
+    // TODO: this sucks, the property should exist on the prototype
+    // but it does not.
+    try {
+        if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) {
+            wsbt = true;
+        }
+    } catch (exc) {
+        // Just ignore failed test localhost connections
+    }
+    if (bt && wsbt) {
+        Util.Info("Detected binaryType support in WebSockets");
+        protocols = ['binary', 'base64'];
+    } else {
+        Util.Info("No binaryType support in WebSockets, using base64 encoding");
+        protocols = 'base64';
+    }
 }
 
 function open(uri) {
@@ -272,19 +332,22 @@ function open(uri) {
     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");
     };