From fcff386b926ad774cb4f7cf4e947a66b1c5580e3 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 16 Aug 2012 13:31:31 -0500 Subject: [PATCH 1/3] websock.js: simpler binary support, protocols param. Use a simpler method of enabling binary transfer over WebSockets. This still presents the user of websock.js with a plain javascript array for the receive queue data. However, if binary support is supported and requested then the transfer will be raw frames instead of base64 encoded. Lots of room for optimization here but for now correct is better than fast. Pull from websockify 17175afd7311c55abd8d --- include/rfb.js | 9 +++-- include/util.js | 4 -- include/websock.js | 99 ++++++++++++++++++++++------------------------ 3 files changed, 52 insertions(+), 60 deletions(-) diff --git a/include/rfb.js b/include/rfb.js index 2a321d24..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"); } @@ -1252,11 +1253,11 @@ encHandlers.HEXTILE = function display_hextile() { rQi += FBU.bytes - 1; } else { if (FBU.subencoding & 0x02) { // Background - FBU.background = rQ.subarray(rQi, rQi + fb_Bpp); + FBU.background = rQ.slice(rQi, rQi + fb_Bpp); rQi += fb_Bpp; } if (FBU.subencoding & 0x04) { // Foreground - FBU.foreground = rQ.subarray(rQi, rQi + fb_Bpp); + FBU.foreground = rQ.slice(rQi, rQi + fb_Bpp); rQi += fb_Bpp; } @@ -1266,7 +1267,7 @@ encHandlers.HEXTILE = function display_hextile() { rQi += 1; for (s = 0; s < subrects; s += 1) { if (FBU.subencoding & 0x10) { // SubrectsColoured - color = rQ.subarray(rQi, rQi + fb_Bpp); + color = rQ.slice(rQi, rQi + fb_Bpp); rQi += fb_Bpp; } else { color = FBU.foreground; diff --git a/include/util.js b/include/util.js index 030afb41..57ccb540 100644 --- a/include/util.js +++ b/include/util.js @@ -18,10 +18,6 @@ var Util = {}; * Make arrays quack */ -Array.prototype.subarray = function (start, end) { - this.slice(start, end); -}; - Array.prototype.push8 = function (num) { this.push(num & 0xFF); }; diff --git a/include/websock.js b/include/websock.js index e3f9d2af..6402eb28 100644 --- a/include/websock.js +++ b/include/websock.js @@ -61,7 +61,6 @@ 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 @@ -125,46 +124,24 @@ 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 = rQslice(0, len); + var arr = rQ.slice(rQi, rQi + len); rQi += len; return String.fromCharCode.apply(null, arr); } function rQshiftBytes(len) { if (typeof(len) === 'undefined') { len = rQlen(); } - var a = rQslice(0, len), b = []; - if (mode === 'binary') { - // Convert to plain array - b.push.apply(b, a); - } else { - // Already plain array, just return the original - b = a - } rQi += len; - return b; + return rQ.slice(rQi-len, rQi); } -function rQshiftArray(len) { - if (typeof(len) === 'undefined') { len = rQlen(); } - var a = rQslice(0, len); - rQi += len; - return a; + +function rQslice(start, end) { + if (end) { + return rQ.slice(rQi + start, rQi + end); + } else { + return rQ.slice(rQi + start); + } } // Check to see if we must wait for 'num' bytes (default to FBU.bytes) @@ -202,14 +179,10 @@ function encode_message() { function decode_message(data) { //Util.Debug(">> decode_message: " + data); 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; + // push arraybuffer values onto the end + rQ.push.apply(rQ, (new Uint8Array(data))); } else { - /* base64 decode and concat to the end */ + // base64 decode and concat to the end rQ = rQ.concat(Base64.decode(data, 0)); } //Util.Debug(">> decode_message, rQ: " + rQ); @@ -265,7 +238,7 @@ function recv_message(e) { // Compact the receive queue if (rQ.length > rQmax) { //Util.Debug("Compacting receive queue"); - rQ = rQslice(rQi); + rQ = rQ.slice(rQi); rQi = 0; } } else { @@ -294,40 +267,62 @@ function on(evt, handler) { eventHandlers[evt] = handler; } -function init() { +function init(protocols) { rQ = []; rQi = 0; sQ = []; - websocket = null, - protocols = "base64"; + websocket = null; var bt = false, - wsbt = 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 } - 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'; + + // 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 = {}; From fa5b334dcbe7a5dab21580b54cc2f5f142600379 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Tue, 21 Aug 2012 09:46:11 -0500 Subject: [PATCH 2/3] webutil.js: use decodeURIComponent on getQueryVar values. --- include/webutil.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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; + } }; From 625040fc909961c8f8b7fea0049b613348b17f84 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Tue, 28 Aug 2012 17:39:02 -0500 Subject: [PATCH 3/3] README: simplify projects/companies. News/help/contact section. Instead of continuing to maintain the full list of project/companies that use noVNC in multiple places (README, wiki, web page) just link to the wiki page. Link to noVNC discussion group page. Link to issues page. Link to Amazon wishlist and non-profits for appreciation. --- README.md | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8bfeb317..cfdac8f9 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,37 @@ noVNC is a HTML5 VNC client that runs well in any modern browser including mobile browsers (iPhone/iPad and Android). +More than 16 companies/projects have integrated noVNC into their +products including [Ganeti Web +Manager](http://code.osuosl.org/projects/ganeti-webmgr), +[OpenStack](http://www.openstack.org), and +[OpenNebula](http://opennebula.org/). See [the Projects and Companies +wiki page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC) +for more complete list. + +### News/help/contact + Notable commits, announcements and news are posted to @noVNC -There are many companies/projects that have integrated noVNC into -their products including: [Ganeti Web Manager](http://code.osuosl.org/projects/ganeti-webmgr), [Archipel](http://archipelproject.org), [openQRM](http://www.openqrm.com/), [OpenNode](http://www.opennodecloud.com/), [OpenStack](http://www.openstack.org), [Broadway (HTML5 GDK/GTK+ backend)](http://blogs.gnome.org/alexl/2011/03/15/gtk-html-backend-update/), [OpenNebula](http://opennebula.org/), [CloudSigma](http://www.cloudsigma.com/), [Zentyal (formerly eBox)](http://www.zentyal.org/), [SlapOS](http://www.slapos.org), [Intel MeshCentral](https://meshcentral.com), [Amahi](http://amahi.org), [Brightbox](http://brightbox.com/), [Foreman](http://theforeman.org), [LibVNCServer](http://libvncserver.sourceforge.net) and [PocketVNC](http://www.pocketvnc.com/blog/?page_id=866). See [this wiki page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC) for more info and links. +If you are a noVNC developer/integrator/user (or want to be) please +join the noVNC +discussion group + +Bugs and feature requests can be submitted via [github +issues](https://github.com/kanaka/noVNC/issues). If you are looking +for a place to start contributing to noVNC, a good place to start +would be the issues that I have marked as +["patchwelcome"](https://github.com/kanaka/noVNC/issues?labels=patchwelcome). + +If you want to show appreciation for noVNC you could buy something off +my [Amazon wishlist](http://www.amazon.com/registry/wishlist/XTXFXK39IA8C/?reveal=unpurchased&sort=priority&layout=compact) or you could donate to a great non-profits such as: [Compassion +International](http://www.compassion.com/), [SIL](http://www.sil.org), +[Habitat for Humanity](http://www.habitat.org), [Electronic Frontier +Foundation](https://www.eff.org/), [Against Malaria +Foundation](http://www.againstmalaria.com/), [Nothing But +Nets](http://www.nothingbutnets.net/), etc. ### Features @@ -89,7 +115,7 @@ a python proxy included ('websockify'). ### Authors/Contributors * noVNC : Joel Martin (github.com/kanaka) - * New UI and Icons : Chris Gordon + * UI and Icons : Chris Gordon * Original Logo : Michael Sersen * tight encoding : Michael Tinglof (Mercuri.ca)