summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Mannehed <samuel@cendio.se>2018-05-04 16:21:27 +0200
committerSamuel Mannehed <samuel@cendio.se>2018-05-07 13:02:51 +0200
commit2bb8b28d786f158bc183b15473be33e12830e29f (patch)
treecd023066e6c58c20a30e9e6d7533d25d4fae5533
parent43bbaa8d6e6e2464ecfc78a453ae7782eace984c (diff)
downloadnovnc-2bb8b28d786f158bc183b15473be33e12830e29f.tar.gz
Handle sending large clipboards
Pasting clipboard texts that were larger than 10240 bytes didnt work and caused a crash in noVNC. This commit fixes the crash and adds handling for sending large clipboard texts. Fixes issue #1065.
-rw-r--r--core/rfb.js43
-rw-r--r--tests/test.rfb.js13
2 files changed, 44 insertions, 12 deletions
diff --git a/core/rfb.js b/core/rfb.js
index 81e1e6a..2d7108d 100644
--- a/core/rfb.js
+++ b/core/rfb.js
@@ -1,7 +1,7 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
- * Copyright (C) 2017 Samuel Mannehed for Cendio AB
+ * Copyright (C) 2018 Samuel Mannehed for Cendio AB
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -1688,19 +1688,40 @@ RFB.messages = {
buff[offset + 2] = 0; // padding
buff[offset + 3] = 0; // padding
- var n = text.length;
+ let length = text.length;
- buff[offset + 4] = n >> 24;
- buff[offset + 5] = n >> 16;
- buff[offset + 6] = n >> 8;
- buff[offset + 7] = n;
+ buff[offset + 4] = length >> 24;
+ buff[offset + 5] = length >> 16;
+ buff[offset + 6] = length >> 8;
+ buff[offset + 7] = length;
- for (var i = 0; i < n; i++) {
- buff[offset + 8 + i] = text.charCodeAt(i);
- }
+ sock._sQlen += 8;
- sock._sQlen += 8 + n;
- sock.flush();
+ // We have to keep track of from where in the text we begin creating the
+ // buffer for the flush in the next iteration.
+ let textOffset = 0;
+
+ let remaining = length;
+ while (remaining > 0) {
+
+ let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen));
+ if (flushSize <= 0) {
+ this._fail("Clipboard contents could not be sent");
+ break;
+ }
+
+ offset = sock._sQlen;
+
+ for (let i = 0; i < flushSize; i++) {
+ buff[offset + i] = text.charCodeAt(textOffset + i);
+ }
+
+ sock._sQlen += flushSize;
+ sock.flush();
+
+ remaining -= flushSize;
+ textOffset += flushSize;
+ }
},
setDesktopSize: function (sock, width, height, id, flags) {
diff --git a/tests/test.rfb.js b/tests/test.rfb.js
index 8f5ee49..7f09416 100644
--- a/tests/test.rfb.js
+++ b/tests/test.rfb.js
@@ -287,12 +287,23 @@ describe('Remote Frame Buffer Protocol Client', function() {
describe('#clipboardPasteFrom', function () {
it('should send the given text in a paste event', function () {
- var expected = {_sQ: new Uint8Array(11), _sQlen: 0, flush: function () {}};
+ var expected = {_sQ: new Uint8Array(11), _sQlen: 0,
+ _sQbufferSize: 11, flush: function () {}};
RFB.messages.clientCutText(expected, 'abc');
client.clipboardPasteFrom('abc');
expect(client._sock).to.have.sent(expected._sQ);
});
+ it('should flush multiple times for large clipboards', function () {
+ sinon.spy(client._sock, 'flush');
+ let long_text = "";
+ for (let i = 0; i < client._sock._sQbufferSize + 100; i++) {
+ long_text += 'a';
+ }
+ client.clipboardPasteFrom(long_text);
+ expect(client._sock.flush).to.have.been.calledTwice;
+ });
+
it('should not send the text if we are not in a normal state', function () {
sinon.spy(client._sock, 'flush');
client._rfb_connection_state = "connecting";