summaryrefslogtreecommitdiff
path: root/tests/test.rfb.js
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test.rfb.js')
-rw-r--r--tests/test.rfb.js455
1 files changed, 439 insertions, 16 deletions
diff --git a/tests/test.rfb.js b/tests/test.rfb.js
index ba35b9c..bb690ce 100644
--- a/tests/test.rfb.js
+++ b/tests/test.rfb.js
@@ -2,7 +2,11 @@ const expect = chai.expect;
import RFB from '../core/rfb.js';
import Websock from '../core/websock.js';
+import ZStream from "../vendor/pako/lib/zlib/zstream.js";
+import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js";
import { encodings } from '../core/encodings.js';
+import { toUnsigned32bit } from '../core/util/int.js';
+import { encodeUTF8 } from '../core/util/strings.js';
import FakeWebSocket from './fake.websocket.js';
@@ -48,6 +52,35 @@ function pushString(arr, string) {
}
}
+function deflateWithSize(data) {
+ // Adds the size of the string in front before deflating
+
+ let unCompData = [];
+ unCompData.push((data.length >> 24) & 0xFF,
+ (data.length >> 16) & 0xFF,
+ (data.length >> 8) & 0xFF,
+ (data.length & 0xFF));
+
+ for (let i = 0; i < data.length; i++) {
+ unCompData.push(data.charCodeAt(i));
+ }
+
+ let strm = new ZStream();
+ let chunkSize = 1024 * 10 * 10;
+ strm.output = new Uint8Array(chunkSize);
+ deflateInit(strm, 5);
+
+ strm.input = unCompData;
+ strm.avail_in = strm.input.length;
+ strm.next_in = 0;
+ strm.next_out = 0;
+ strm.avail_out = chunkSize;
+
+ deflate(strm, 3);
+
+ return new Uint8Array(strm.output.buffer, 0, strm.next_out);
+}
+
describe('Remote Frame Buffer Protocol Client', function () {
let clock;
let raf;
@@ -291,12 +324,39 @@ describe('Remote Frame Buffer Protocol Client', function () {
});
describe('#clipboardPasteFrom', function () {
- it('should send the given text in a paste event', function () {
- const expected = {_sQ: new Uint8Array(11), _sQlen: 0,
- _sQbufferSize: 11, flush: () => {}};
- RFB.messages.clientCutText(expected, 'abc');
- client.clipboardPasteFrom('abc');
- expect(client._sock).to.have.sent(expected._sQ);
+ describe('Clipboard update handling', function () {
+ beforeEach(function () {
+ sinon.spy(RFB.messages, 'clientCutText');
+ sinon.spy(RFB.messages, 'extendedClipboardNotify');
+ });
+
+ afterEach(function () {
+ RFB.messages.clientCutText.restore();
+ RFB.messages.extendedClipboardNotify.restore();
+ });
+
+ it('should send the given text in an clipboard update', function () {
+ client.clipboardPasteFrom('abc');
+
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(client._sock,
+ new Uint8Array([97, 98, 99]));
+ });
+
+ it('should send an notify if extended clipboard is supported by server', function () {
+ // Send our capabilities
+ let data = [3, 0, 0, 0];
+ const flags = [0x1F, 0x00, 0x00, 0x01];
+ let fileSizes = [0x00, 0x00, 0x00, 0x1E];
+
+ push32(data, toUnsigned32bit(-8));
+ data = data.concat(flags);
+ data = data.concat(fileSizes);
+ client._sock._websocket._receive_data(new Uint8Array(data));
+
+ client.clipboardPasteFrom('extended test');
+ expect(RFB.messages.extendedClipboardNotify).to.have.been.calledOnce;
+ });
});
it('should flush multiple times for large clipboards', function () {
@@ -2336,17 +2396,217 @@ describe('Remote Frame Buffer Protocol Client', function () {
});
});
- it('should fire the clipboard callback with the retrieved text on ServerCutText', function () {
- const expected_str = 'cheese!';
- const data = [3, 0, 0, 0];
- push32(data, expected_str.length);
- for (let i = 0; i < expected_str.length; i++) { data.push(expected_str.charCodeAt(i)); }
- const spy = sinon.spy();
- client.addEventListener("clipboard", spy);
+ describe('Normal Clipboard Handling Receive', function () {
+ it('should fire the clipboard callback with the retrieved text on ServerCutText', function () {
+ const expected_str = 'cheese!';
+ const data = [3, 0, 0, 0];
+ push32(data, expected_str.length);
+ for (let i = 0; i < expected_str.length; i++) { data.push(expected_str.charCodeAt(i)); }
+ const spy = sinon.spy();
+ client.addEventListener("clipboard", spy);
+
+ client._sock._websocket._receive_data(new Uint8Array(data));
+ expect(spy).to.have.been.calledOnce;
+ expect(spy.args[0][0].detail.text).to.equal(expected_str);
+ });
+ });
+
+ describe('Extended clipboard Handling', function () {
+
+ describe('Extended clipboard initialization', function () {
+ beforeEach(function () {
+ sinon.spy(RFB.messages, 'extendedClipboardCaps');
+ });
+
+ afterEach(function () {
+ RFB.messages.extendedClipboardCaps.restore();
+ });
+
+ it('should update capabilities when receiving a Caps message', function () {
+ let data = [3, 0, 0, 0];
+ const flags = [0x1F, 0x00, 0x00, 0x03];
+ let fileSizes = [0x00, 0x00, 0x00, 0x1E,
+ 0x00, 0x00, 0x00, 0x3C];
+
+ push32(data, toUnsigned32bit(-12));
+ data = data.concat(flags);
+ data = data.concat(fileSizes);
+ client._sock._websocket._receive_data(new Uint8Array(data));
+
+ // Check that we give an response caps when we receive one
+ expect(RFB.messages.extendedClipboardCaps).to.have.been.calledOnce;
+
+ // FIXME: Can we avoid checking internal variables?
+ expect(client._clipboardServerCapabilitiesFormats[0]).to.not.equal(true);
+ expect(client._clipboardServerCapabilitiesFormats[1]).to.equal(true);
+ expect(client._clipboardServerCapabilitiesFormats[2]).to.equal(true);
+ expect(client._clipboardServerCapabilitiesActions[(1 << 24)]).to.equal(true);
+ });
+
+
+ });
+
+ describe('Extended Clipboard Handling Receive', function () {
+
+ beforeEach(function () {
+ // Send our capabilities
+ let data = [3, 0, 0, 0];
+ const flags = [0x1F, 0x00, 0x00, 0x01];
+ let fileSizes = [0x00, 0x00, 0x00, 0x1E];
+
+ push32(data, toUnsigned32bit(-8));
+ data = data.concat(flags);
+ data = data.concat(fileSizes);
+ client._sock._websocket._receive_data(new Uint8Array(data));
+ });
+
+ describe('Handle Provide', function () {
+ it('should update clipboard with correct Unicode data from a Provide message', function () {
+ let expectedData = "Aå漢字!";
+ let data = [3, 0, 0, 0];
+ const flags = [0x10, 0x00, 0x00, 0x01];
+
+ /* The size 10 (utf8 encoded string size) and the
+ string "Aå漢字!" utf8 encoded and deflated. */
+ let deflatedData = [120, 94, 99, 96, 96, 224, 114, 60,
+ 188, 244, 217, 158, 69, 79, 215,
+ 78, 87, 4, 0, 35, 207, 6, 66];
+
+ // How much data we are sending.
+ push32(data, toUnsigned32bit(-(4 + deflatedData.length)));
+
+ data = data.concat(flags);
+ data = data.concat(deflatedData);
+
+ const spy = sinon.spy();
+ client.addEventListener("clipboard", spy);
+
+ client._sock._websocket._receive_data(new Uint8Array(data));
+ expect(spy).to.have.been.calledOnce;
+ expect(spy.args[0][0].detail.text).to.equal(expectedData);
+ client.removeEventListener("clipboard", spy);
+ });
+
+ it('should update clipboard with correct escape characters from a Provide message ', function () {
+ let expectedData = "Oh\nmy!";
+ let data = [3, 0, 0, 0];
+ const flags = [0x10, 0x00, 0x00, 0x01];
+
+ let text = encodeUTF8("Oh\r\nmy!\0");
+
+ let deflatedText = deflateWithSize(text);
+
+ // How much data we are sending.
+ push32(data, toUnsigned32bit(-(4 + deflatedText.length)));
+
+ data = data.concat(flags);
+
+ let sendData = new Uint8Array(data.length + deflatedText.length);
+ sendData.set(data);
+ sendData.set(deflatedText, data.length);
+
+ const spy = sinon.spy();
+ client.addEventListener("clipboard", spy);
+
+ client._sock._websocket._receive_data(sendData);
+ expect(spy).to.have.been.calledOnce;
+ expect(spy.args[0][0].detail.text).to.equal(expectedData);
+ client.removeEventListener("clipboard", spy);
+ });
+
+ });
+
+ describe('Handle Notify', function () {
+ beforeEach(function () {
+ sinon.spy(RFB.messages, 'extendedClipboardRequest');
+ });
+
+ afterEach(function () {
+ RFB.messages.extendedClipboardRequest.restore();
+ });
+
+ it('should make a request with supported formats when receiving a notify message', function () {
+ let data = [3, 0, 0, 0];
+ const flags = [0x08, 0x00, 0x00, 0x07];
+ push32(data, toUnsigned32bit(-4));
+ data = data.concat(flags);
+ let expectedData = [0x01];
+
+ client._sock._websocket._receive_data(new Uint8Array(data));
+
+ expect(RFB.messages.extendedClipboardRequest).to.have.been.calledOnce;
+ expect(RFB.messages.extendedClipboardRequest).to.have.been.calledWith(client._sock, expectedData);
+ });
+ });
+
+ describe('Handle Peek', function () {
+ beforeEach(function () {
+ sinon.spy(RFB.messages, 'extendedClipboardNotify');
+ });
+
+ afterEach(function () {
+ RFB.messages.extendedClipboardNotify.restore();
+ });
+
+ it('should send an empty Notify when receiving a Peek and no excisting clipboard data', function () {
+ let data = [3, 0, 0, 0];
+ const flags = [0x04, 0x00, 0x00, 0x00];
+ push32(data, toUnsigned32bit(-4));
+ data = data.concat(flags);
+ let expectedData = [];
+
+ client._sock._websocket._receive_data(new Uint8Array(data));
+
+ expect(RFB.messages.extendedClipboardNotify).to.have.been.calledOnce;
+ expect(RFB.messages.extendedClipboardNotify).to.have.been.calledWith(client._sock, expectedData);
+ });
+
+ it('should send a Notify message with supported formats when receiving a Peek', function () {
+ let data = [3, 0, 0, 0];
+ const flags = [0x04, 0x00, 0x00, 0x00];
+ push32(data, toUnsigned32bit(-4));
+ data = data.concat(flags);
+ let expectedData = [0x01];
+
+ // Needed to have clipboard data to read.
+ // This will trigger a call to Notify, reset history
+ client.clipboardPasteFrom("HejHej");
+ RFB.messages.extendedClipboardNotify.resetHistory();
+
+ client._sock._websocket._receive_data(new Uint8Array(data));
+
+ expect(RFB.messages.extendedClipboardNotify).to.have.been.calledOnce;
+ expect(RFB.messages.extendedClipboardNotify).to.have.been.calledWith(client._sock, expectedData);
+ });
+ });
+
+ describe('Handle Request', function () {
+ beforeEach(function () {
+ sinon.spy(RFB.messages, 'extendedClipboardProvide');
+ });
+
+ afterEach(function () {
+ RFB.messages.extendedClipboardProvide.restore();
+ });
+
+ it('should send a Provide message with supported formats when receiving a Request', function () {
+ let data = [3, 0, 0, 0];
+ const flags = [0x02, 0x00, 0x00, 0x01];
+ push32(data, toUnsigned32bit(-4));
+ data = data.concat(flags);
+ let expectedData = [0x01];
+
+ client.clipboardPasteFrom("HejHej");
+ expect(RFB.messages.extendedClipboardProvide).to.not.have.been.called;
+
+ client._sock._websocket._receive_data(new Uint8Array(data));
+
+ expect(RFB.messages.extendedClipboardProvide).to.have.been.calledOnce;
+ expect(RFB.messages.extendedClipboardProvide).to.have.been.calledWith(client._sock, expectedData, ["HejHej"]);
+ });
+ });
+ });
- client._sock._websocket._receive_data(new Uint8Array(data));
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.text).to.equal(expected_str);
});
it('should fire the bell callback on Bell', function () {
@@ -2574,3 +2834,166 @@ describe('Remote Frame Buffer Protocol Client', function () {
});
});
});
+
+describe('RFB messages', function () {
+ let sock;
+
+ before(function () {
+ FakeWebSocket.replace();
+ sock = new Websock();
+ sock.open();
+ });
+
+ after(function () {
+ FakeWebSocket.restore();
+ });
+
+ describe('Extended Clipboard Handling Send', function () {
+ beforeEach(function () {
+ sinon.spy(RFB.messages, 'clientCutText');
+ });
+
+ afterEach(function () {
+ RFB.messages.clientCutText.restore();
+ });
+
+ it('should call clientCutText with correct Caps data', function () {
+ let formats = {
+ 0: 2,
+ 2: 4121
+ };
+ let expectedData = new Uint8Array([0x1F, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x10, 0x19]);
+ let actions = [
+ 1 << 24, // Caps
+ 1 << 25, // Request
+ 1 << 26, // Peek
+ 1 << 27, // Notify
+ 1 << 28 // Provide
+ ];
+
+ RFB.messages.extendedClipboardCaps(sock, actions, formats);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData);
+ });
+
+ it('should call clientCutText with correct Request data', function () {
+ let formats = new Uint8Array([0x01]);
+ let expectedData = new Uint8Array([0x02, 0x00, 0x00, 0x01]);
+
+ RFB.messages.extendedClipboardRequest(sock, formats);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData);
+ });
+
+ it('should call clientCutText with correct Notify data', function () {
+ let formats = new Uint8Array([0x01]);
+ let expectedData = new Uint8Array([0x08, 0x00, 0x00, 0x01]);
+
+ RFB.messages.extendedClipboardNotify(sock, formats);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData);
+ });
+
+ it('should call clientCutText with correct Provide data', function () {
+ let testText = "Test string";
+ let expectedText = encodeUTF8(testText + "\0");
+
+ let deflatedData = deflateWithSize(expectedText);
+
+ // Build Expected with flags and deflated data
+ let expectedData = new Uint8Array(4 + deflatedData.length);
+ expectedData[0] = 0x10; // The client capabilities
+ expectedData[1] = 0x00; // Reserved flags
+ expectedData[2] = 0x00; // Reserved flags
+ expectedData[3] = 0x01; // The formats client supports
+ expectedData.set(deflatedData, 4);
+
+ RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true);
+
+ });
+
+ describe('End of line characters', function () {
+ it('Carriage return', function () {
+
+ let testText = "Hello\rworld\r\r!";
+ let expectedText = encodeUTF8("Hello\r\nworld\r\n\r\n!\0");
+
+ let deflatedData = deflateWithSize(expectedText);
+
+ // Build Expected with flags and deflated data
+ let expectedData = new Uint8Array(4 + deflatedData.length);
+ expectedData[0] = 0x10; // The client capabilities
+ expectedData[1] = 0x00; // Reserved flags
+ expectedData[2] = 0x00; // Reserved flags
+ expectedData[3] = 0x01; // The formats client supports
+ expectedData.set(deflatedData, 4);
+
+ RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true);
+ });
+
+ it('Carriage return Line feed', function () {
+
+ let testText = "Hello\r\n\r\nworld\r\n!";
+ let expectedText = encodeUTF8(testText + "\0");
+
+ let deflatedData = deflateWithSize(expectedText);
+
+ // Build Expected with flags and deflated data
+ let expectedData = new Uint8Array(4 + deflatedData.length);
+ expectedData[0] = 0x10; // The client capabilities
+ expectedData[1] = 0x00; // Reserved flags
+ expectedData[2] = 0x00; // Reserved flags
+ expectedData[3] = 0x01; // The formats client supports
+ expectedData.set(deflatedData, 4);
+
+ RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true);
+ });
+
+ it('Line feed', function () {
+ let testText = "Hello\n\n\nworld\n!";
+ let expectedText = encodeUTF8("Hello\r\n\r\n\r\nworld\r\n!\0");
+
+ let deflatedData = deflateWithSize(expectedText);
+
+ // Build Expected with flags and deflated data
+ let expectedData = new Uint8Array(4 + deflatedData.length);
+ expectedData[0] = 0x10; // The client capabilities
+ expectedData[1] = 0x00; // Reserved flags
+ expectedData[2] = 0x00; // Reserved flags
+ expectedData[3] = 0x01; // The formats client supports
+ expectedData.set(deflatedData, 4);
+
+ RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true);
+ });
+
+ it('Carriage return and Line feed mixed', function () {
+ let testText = "\rHello\r\n\rworld\n\n!";
+ let expectedText = encodeUTF8("\r\nHello\r\n\r\nworld\r\n\r\n!\0");
+
+ let deflatedData = deflateWithSize(expectedText);
+
+ // Build Expected with flags and deflated data
+ let expectedData = new Uint8Array(4 + deflatedData.length);
+ expectedData[0] = 0x10; // The client capabilities
+ expectedData[1] = 0x00; // Reserved flags
+ expectedData[2] = 0x00; // Reserved flags
+ expectedData[3] = 0x01; // The formats client supports
+ expectedData.set(deflatedData, 4);
+
+ RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]);
+ expect(RFB.messages.clientCutText).to.have.been.calledOnce;
+ expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true);
+ });
+ });
+ });
+});