diff options
author | Samuel Mannehed <samuel@cendio.se> | 2018-05-04 16:21:27 +0200 |
---|---|---|
committer | Samuel Mannehed <samuel@cendio.se> | 2018-05-07 13:02:51 +0200 |
commit | 2bb8b28d786f158bc183b15473be33e12830e29f (patch) | |
tree | cd023066e6c58c20a30e9e6d7533d25d4fae5533 | |
parent | 43bbaa8d6e6e2464ecfc78a453ae7782eace984c (diff) | |
download | novnc-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.js | 43 | ||||
-rw-r--r-- | tests/test.rfb.js | 13 |
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"; |