Commit cd1ab146 authored by Solly's avatar Solly

Merge pull request #474 from kanaka/bug/throw-error-from-constructor

Throw exceptions from RFB constructor
parents 245dc866 d9fc1c7b
...@@ -86,29 +86,9 @@ var Display; ...@@ -86,29 +86,9 @@ var Display;
} }
// Determine browser support for setting the cursor via data URI scheme // Determine browser support for setting the cursor via data URI scheme
var curDat = []; if (this._cursor_uri || this._cursor_uri === null ||
for (var i = 0; i < 8 * 8 * 4; i++) { this._cursor_uri === undefined) {
curDat.push(255); this._cursor_uri = Util.browserSupportsCursorURIs(this._target);
}
try {
var curSave = this._target.style.cursor;
Display.changeCursor(this._target, curDat, curDat, 2, 2, 8, 8);
if (this._target.style.cursor) {
if (this._cursor_uri === null || this._cursor_uri === undefined) {
this._cursor_uri = true;
}
Util.Info("Data URI scheme cursor supported");
this._target.style.cursor = curSave;
} else {
if (this._cursor_uri === null || this._cursor_uri === undefined) {
this._cursor_uri = false;
}
Util.Warn("Data URI scheme cursor not supported");
this._target.style.cursor = "none";
}
} catch (exc) {
Util.Error("Data URI scheme cursor test exception: " + exc);
this._cursor_uri = false;
} }
Util.Debug("<< Display.constructor"); Util.Debug("<< Display.constructor");
......
...@@ -159,11 +159,13 @@ var RFB; ...@@ -159,11 +159,13 @@ var RFB;
this._encStats[this._encodings[i][1]] = [0, 0]; this._encStats[this._encodings[i][1]] = [0, 0];
} }
// NB: nothing that needs explicit teardown should be done
// before this point, since this can throw an exception
try { try {
this._display = new Display({target: this._target}); this._display = new Display({target: this._target});
} catch (exc) { } catch (exc) {
Util.Error("Display exception: " + exc); Util.Error("Display exception: " + exc);
this._updateState('fatal', "No working Display"); throw exc;
} }
this._keyboard = new Keyboard({target: this._focusContainer, this._keyboard = new Keyboard({target: this._focusContainer,
...@@ -217,9 +219,11 @@ var RFB; ...@@ -217,9 +219,11 @@ var RFB;
} else { } else {
Util.Warn("Using web-socket-js bridge. Flash version: " + Util.Flash.version); Util.Warn("Using web-socket-js bridge. Flash version: " + Util.Flash.version);
if (!Util.Flash || Util.Flash.version < 9) { if (!Util.Flash || Util.Flash.version < 9) {
this._updateState('fatal', "WebSockets or <a href='http://get.adobe.com/flashplayer'>Adobe Flash</a> is required"); this._cleanupSocket('fatal');
throw new Exception("WebSockets or <a href='http://get.adobe.com/flashplayer'>Adobe Flash</a> is required");
} else if (document.location.href.substr(0, 7) === 'file://') { } else if (document.location.href.substr(0, 7) === 'file://') {
this._updateState('fatal', "'file://' URL is incompatible with Adobe Flash"); this._cleanupSocket('fatal');
throw new Exception("'file://' URL is incompatible with Adobe Flash");
} else { } else {
this._updateState('loaded', 'noVNC ready: WebSockets emulation, ' + rmode); this._updateState('loaded', 'noVNC ready: WebSockets emulation, ' + rmode);
} }
...@@ -398,6 +402,32 @@ var RFB; ...@@ -398,6 +402,32 @@ var RFB;
} }
}, },
_cleanupSocket: function (state) {
if (this._sendTimer) {
clearInterval(this._sendTimer);
this._sendTimer = null;
}
if (this._msgTimer) {
clearInterval(this._msgTimer);
this._msgTimer = null;
}
if (this._display && this._display.get_context()) {
this._keyboard.ungrab();
this._mouse.ungrab();
if (state !== 'connect' && state !== 'loaded') {
this._display.defaultCursor();
}
if (Util.get_logging() !== 'debug' || state === 'loaded') {
// Show noVNC logo on load and when disconnected, unless in
// debug mode
this._display.clear();
}
}
this._sock.close();
},
/* /*
* Page states: * Page states:
...@@ -432,31 +462,7 @@ var RFB; ...@@ -432,31 +462,7 @@ var RFB;
*/ */
if (state in {'disconnected': 1, 'loaded': 1, 'connect': 1, if (state in {'disconnected': 1, 'loaded': 1, 'connect': 1,
'disconnect': 1, 'failed': 1, 'fatal': 1}) { 'disconnect': 1, 'failed': 1, 'fatal': 1}) {
this._cleanupSocket(state);
if (this._sendTimer) {
clearInterval(this._sendTimer);
this._sendTimer = null;
}
if (this._msgTimer) {
clearInterval(this._msgTimer);
this._msgTimer = null;
}
if (this._display && this._display.get_context()) {
this._keyboard.ungrab();
this._mouse.ungrab();
if (state !== 'connect' && state !== 'loaded') {
this._display.defaultCursor();
}
if (Util.get_logging() !== 'debug' || state === 'loaded') {
// Show noVNC logo on load and when disconnected, unless in
// debug mode
this._display.clear();
}
}
this._sock.close();
} }
if (oldstate === 'fatal') { if (oldstate === 'fatal') {
......
...@@ -97,8 +97,6 @@ var UI; ...@@ -97,8 +97,6 @@ var UI;
UI.initSetting('path', 'websockify'); UI.initSetting('path', 'websockify');
UI.initSetting('repeaterID', ''); UI.initSetting('repeaterID', '');
UI.initRFB();
var autoconnect = WebUtil.getQueryVar('autoconnect', false); var autoconnect = WebUtil.getQueryVar('autoconnect', false);
if (autoconnect === 'true' || autoconnect == '1') { if (autoconnect === 'true' || autoconnect == '1') {
autoconnect = true; autoconnect = true;
...@@ -136,7 +134,7 @@ var UI; ...@@ -136,7 +134,7 @@ var UI;
Util.addEvent(window, 'load', UI.keyboardinputReset); Util.addEvent(window, 'load', UI.keyboardinputReset);
Util.addEvent(window, 'beforeunload', function () { Util.addEvent(window, 'beforeunload', function () {
if (UI.rfb_state === 'normal') { if (UI.rfb && UI.rfb_state === 'normal') {
return "You are currently connected."; return "You are currently connected.";
} }
} ); } );
...@@ -161,13 +159,19 @@ var UI; ...@@ -161,13 +159,19 @@ var UI;
}, },
initRFB: function () { initRFB: function () {
UI.rfb = new RFB({'target': $D('noVNC_canvas'), try {
'onUpdateState': UI.updateState, UI.rfb = new RFB({'target': $D('noVNC_canvas'),
'onXvpInit': UI.updateXvpVisualState, 'onUpdateState': UI.updateState,
'onClipboard': UI.clipReceive, 'onXvpInit': UI.updateXvpVisualState,
'onFBUComplete': UI.FBUComplete, 'onClipboard': UI.clipReceive,
'onFBResize': UI.updateViewDragButton, 'onFBUComplete': UI.FBUComplete,
'onDesktopName': UI.updateDocumentTitle}); 'onFBResize': UI.updateViewDragButton,
'onDesktopName': UI.updateDocumentTitle});
return true;
} catch (exc) {
UI.updateState(null, 'fatal', null, 'Unable to create RFB client -- ' + exc);
return false;
}
}, },
addMouseHandlers: function() { addMouseHandlers: function() {
...@@ -213,12 +217,14 @@ var UI; ...@@ -213,12 +217,14 @@ var UI;
$D("noVNC_connect_button").onclick = UI.connect; $D("noVNC_connect_button").onclick = UI.connect;
$D("noVNC_resize").onchange = function () { $D("noVNC_resize").onchange = function () {
var connected = UI.rfb_state === 'normal' ? true : false; var connected = UI.rfb && UI.rfb_state === 'normal';
UI.enableDisableClip(connected); UI.enableDisableClip(connected);
}; };
}, },
onresize: function (callback) { onresize: function (callback) {
if (!UI.rfb) return;
var size = UI.getCanvasLimit(); var size = UI.getCanvasLimit();
if (size && UI.rfb_state === 'normal' && UI.rfb.get_display()) { if (size && UI.rfb_state === 'normal' && UI.rfb.get_display()) {
...@@ -480,7 +486,7 @@ var UI; ...@@ -480,7 +486,7 @@ var UI;
} else { } else {
UI.updateSetting('encrypt'); UI.updateSetting('encrypt');
UI.updateSetting('true_color'); UI.updateSetting('true_color');
if (UI.rfb.get_display().get_cursor_uri()) { if (Util.browserSupportsCursorURIs()) {
UI.updateSetting('cursor'); UI.updateSetting('cursor');
} else { } else {
UI.updateSetting('cursor', !UI.isTouchDevice); UI.updateSetting('cursor', !UI.isTouchDevice);
...@@ -536,7 +542,7 @@ var UI; ...@@ -536,7 +542,7 @@ var UI;
//Util.Debug(">> settingsApply"); //Util.Debug(">> settingsApply");
UI.saveSetting('encrypt'); UI.saveSetting('encrypt');
UI.saveSetting('true_color'); UI.saveSetting('true_color');
if (UI.rfb.get_display().get_cursor_uri()) { if (Util.browserSupportsCursorURIs()) {
UI.saveSetting('cursor'); UI.saveSetting('cursor');
} }
...@@ -558,7 +564,7 @@ var UI; ...@@ -558,7 +564,7 @@ var UI;
WebUtil.selectStylesheet(UI.getSetting('stylesheet')); WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
WebUtil.init_logging(UI.getSetting('logging')); WebUtil.init_logging(UI.getSetting('logging'));
UI.setViewClip(); UI.setViewClip();
UI.setViewDrag(UI.rfb.get_viewportDrag()); UI.setViewDrag(UI.rfb && UI.rfb.get_viewportDrag());
//Util.Debug("<< settingsApply"); //Util.Debug("<< settingsApply");
}, },
...@@ -642,13 +648,6 @@ var UI; ...@@ -642,13 +648,6 @@ var UI;
break; break;
} }
switch (state) {
case 'fatal':
case 'failed':
case 'disconnected':
UI.initRFB();
}
if (typeof(msg) !== 'undefined') { if (typeof(msg) !== 'undefined') {
$D('noVNC-control-bar').setAttribute("class", klass); $D('noVNC-control-bar').setAttribute("class", klass);
$D('noVNC_status').innerHTML = msg; $D('noVNC_status').innerHTML = msg;
...@@ -659,13 +658,12 @@ var UI; ...@@ -659,13 +658,12 @@ var UI;
// Disable/enable controls depending on connection state // Disable/enable controls depending on connection state
updateVisualState: function() { updateVisualState: function() {
var connected = UI.rfb_state === 'normal' ? true : false; var connected = UI.rfb && UI.rfb_state === 'normal';
//Util.Debug(">> updateVisualState"); //Util.Debug(">> updateVisualState");
$D('noVNC_encrypt').disabled = connected; $D('noVNC_encrypt').disabled = connected;
$D('noVNC_true_color').disabled = connected; $D('noVNC_true_color').disabled = connected;
if (UI.rfb && UI.rfb.get_display() && if (Util.browserSupportsCursorURIs()) {
UI.rfb.get_display().get_cursor_uri()) {
$D('noVNC_cursor').disabled = connected; $D('noVNC_cursor').disabled = connected;
} else { } else {
UI.updateSetting('cursor', !UI.isTouchDevice); UI.updateSetting('cursor', !UI.isTouchDevice);
...@@ -780,6 +778,8 @@ var UI; ...@@ -780,6 +778,8 @@ var UI;
throw new Error("Must set host and port"); throw new Error("Must set host and port");
} }
if (!UI.initRFB()) return;
UI.rfb.set_encrypt(UI.getSetting('encrypt')); UI.rfb.set_encrypt(UI.getSetting('encrypt'));
UI.rfb.set_true_color(UI.getSetting('true_color')); UI.rfb.set_true_color(UI.getSetting('true_color'));
UI.rfb.set_local_cursor(UI.getSetting('cursor')); UI.rfb.set_local_cursor(UI.getSetting('cursor'));
...@@ -809,11 +809,15 @@ var UI; ...@@ -809,11 +809,15 @@ var UI;
}, },
displayBlur: function() { displayBlur: function() {
if (!UI.rfb) return;
UI.rfb.get_keyboard().set_focused(false); UI.rfb.get_keyboard().set_focused(false);
UI.rfb.get_mouse().set_focused(false); UI.rfb.get_mouse().set_focused(false);
}, },
displayFocus: function() { displayFocus: function() {
if (!UI.rfb) return;
UI.rfb.get_keyboard().set_focused(true); UI.rfb.get_keyboard().set_focused(true);
UI.rfb.get_mouse().set_focused(true); UI.rfb.get_mouse().set_focused(true);
}, },
...@@ -882,7 +886,7 @@ var UI; ...@@ -882,7 +886,7 @@ var UI;
// Toggle/set/unset the viewport drag/move button // Toggle/set/unset the viewport drag/move button
setViewDrag: function(drag) { setViewDrag: function(drag) {
if (!UI.rfb) { return; } if (!UI.rfb) return;
UI.updateViewDragButton(); UI.updateViewDragButton();
...@@ -953,7 +957,7 @@ var UI; ...@@ -953,7 +957,7 @@ var UI;
// sending keyCodes in the normal keyboard events when using on screen keyboards. // sending keyCodes in the normal keyboard events when using on screen keyboards.
keyInput: function(event) { keyInput: function(event) {
if (!UI.rfb) { return; } if (!UI.rfb) return;
var newValue = event.target.value; var newValue = event.target.value;
......
...@@ -508,6 +508,29 @@ Util.stopEvent = function (e) { ...@@ -508,6 +508,29 @@ Util.stopEvent = function (e) {
else { e.returnValue = false; } else { e.returnValue = false; }
}; };
Util._cursor_uris_supported = null;
Util.browserSupportsCursorURIs = function () {
if (Util._cursor_uris_supported === null) {
try {
var target = document.createElement('canvas');
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
if (target.style.cursor) {
Util.Info("Data URI scheme cursor supported");
Util._cursor_uris_supported = true;
} else {
Util.Warn("Data URI scheme cursor not supported");
Util._cursor_uris_supported = false;
}
} catch (exc) {
Util.Error("Data URI scheme cursor test exception: " + exc);
Util._cursor_uris_supported = false;
}
}
return Util._cursor_uris_supported;
};
// Set browser engine versions. Based on mootools. // Set browser engine versions. Based on mootools.
Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}; Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
......
...@@ -28,35 +28,29 @@ describe('Display/Canvas Helper', function () { ...@@ -28,35 +28,29 @@ describe('Display/Canvas Helper', function () {
describe('checking for cursor uri support', function () { describe('checking for cursor uri support', function () {
beforeEach(function () { beforeEach(function () {
this._old_change_cursor = Display.changeCursor; this._old_browser_supports_cursor_uris = Util.browserSupportsCursorURIs;
}); });
it('should disable cursor URIs if there is no support', function () { it('should disable cursor URIs if there is no support', function () {
Display.changeCursor = function(target) { Util.browserSupportsCursorURIs = function () { return false; };
target.style.cursor = undefined;
};
var display = new Display({ target: document.createElement('canvas'), prefer_js: true, viewport: false }); var display = new Display({ target: document.createElement('canvas'), prefer_js: true, viewport: false });
expect(display._cursor_uri).to.be.false; expect(display._cursor_uri).to.be.false;
}); });
it('should enable cursor URIs if there is support', function () { it('should enable cursor URIs if there is support', function () {
Display.changeCursor = function(target) { Util.browserSupportsCursorURIs = function () { return true; };
target.style.cursor = 'pointer';
};
var display = new Display({ target: document.createElement('canvas'), prefer_js: true, viewport: false }); var display = new Display({ target: document.createElement('canvas'), prefer_js: true, viewport: false });
expect(display._cursor_uri).to.be.true; expect(display._cursor_uri).to.be.true;
}); });
it('respect the cursor_uri option if there is support', function () { it('respect the cursor_uri option if there is support', function () {
Display.changeCursor = function(target) { Util.browserSupportsCursorURIs = function () { return false; };
target.style.cursor = 'pointer';
};
var display = new Display({ target: document.createElement('canvas'), prefer_js: true, viewport: false, cursor_uri: false }); var display = new Display({ target: document.createElement('canvas'), prefer_js: true, viewport: false, cursor_uri: false });
expect(display._cursor_uri).to.be.false; expect(display._cursor_uri).to.be.false;
}); });
afterEach(function () { afterEach(function () {
Display.changeCursor = this._old_change_cursor; Util.browserSupportsCursorURIs = this._old_browser_supports_cursor_uris;
}); });
}); });
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
</head> </head>
<body> <body>
<div id="noVNC-control-bar"> <div id="noVNC-control-bar" class="noVNC_status_normal">
<!--noVNC Mobile Device only Buttons--> <!--noVNC Mobile Device only Buttons-->
<div class="noVNC-buttons-left"> <div class="noVNC-buttons-left">
<input type="image" alt="viewport drag" src="images/drag.png" <input type="image" alt="viewport drag" src="images/drag.png"
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
</div> </div>
</div> </div>
<div id="noVNC_status">Loading</div> <div id="noVNC_status"></div>
<!--noVNC Buttons--> <!--noVNC Buttons-->
<div class="noVNC-buttons-right"> <div class="noVNC-buttons-right">
......
...@@ -216,18 +216,24 @@ ...@@ -216,18 +216,24 @@
return; return;
} }
rfb = new RFB({'target': $D('noVNC_canvas'), try {
'encrypt': WebUtil.getQueryVar('encrypt', rfb = new RFB({'target': $D('noVNC_canvas'),
(window.location.protocol === "https:")), 'encrypt': WebUtil.getQueryVar('encrypt',
'repeaterID': WebUtil.getQueryVar('repeaterID', ''), (window.location.protocol === "https:")),
'true_color': WebUtil.getQueryVar('true_color', true), 'repeaterID': WebUtil.getQueryVar('repeaterID', ''),
'local_cursor': WebUtil.getQueryVar('cursor', true), 'true_color': WebUtil.getQueryVar('true_color', true),
'shared': WebUtil.getQueryVar('shared', true), 'local_cursor': WebUtil.getQueryVar('cursor', true),
'view_only': WebUtil.getQueryVar('view_only', false), 'shared': WebUtil.getQueryVar('shared', true),
'onUpdateState': updateState, 'view_only': WebUtil.getQueryVar('view_only', false),
'onXvpInit': xvpInit, 'onUpdateState': updateState,
'onPasswordRequired': passwordRequired, 'onXvpInit': xvpInit,
'onFBUComplete': FBUComplete}); 'onPasswordRequired': passwordRequired,
'onFBUComplete': FBUComplete});
} catch (exc) {
UI.updateState(null, 'fatal', null, 'Unable to create RFB client -- ' + exc);
return; // don't continue trying to connect
}
rfb.connect(host, port, password, path); rfb.connect(host, port, password, path);
}; };
</script> </script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment