]> git.proxmox.com Git - mirror_novnc.git/commitdiff
Handle sending large clipboards
authorSamuel Mannehed <samuel@cendio.se>
Fri, 4 May 2018 14:21:27 +0000 (16:21 +0200)
committerSamuel Mannehed <samuel@cendio.se>
Mon, 7 May 2018 11:02:51 +0000 (13:02 +0200)
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.

core/rfb.js
tests/test.rfb.js

index 81e1e6adf974ddb833cfcabe9cbea8e4500ad1d5..2d7108d2481904e73133cf7f941c0e5405c9679b 100644 (file)
@@ -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) {
index 8f5ee49af259ae5518f76663c351a44b795ebcc7..7f09416ab5b637b608bb5d6f271e324202e24701 100644 (file)
@@ -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";