]> git.proxmox.com Git - mirror_novnc.git/commitdiff
Always return copy of data from socket
authorPierre Ossman <ossman@cendio.se>
Tue, 16 May 2023 17:06:10 +0000 (19:06 +0200)
committerPierre Ossman <ossman@cendio.se>
Sun, 4 Jun 2023 17:12:02 +0000 (19:12 +0200)
We don't know how long the caller will hang on to this data, so we need
to be safe by default and assume it will kept indefinitely. That means
we can't return a reference to the internal buffer, as that will get
overwritten with future messages.

We want to avoid unnecessary copying in performance critical code,
though. So allow code to explicitly ask for a shared buffer, assuming
they know the data needs to be consumed immediately.

core/decoders/hextile.js
core/decoders/jpeg.js
core/decoders/raw.js
core/decoders/tight.js
core/decoders/zrle.js
core/websock.js
tests/test.websock.js

index 6d96927f72a2e19d36aa075abfaeea2f5eb7a0c8..cc33e0e10ab8bad8443c51b3fd8699547c5323eb 100644 (file)
@@ -86,7 +86,7 @@ export default class HextileDecoder {
                 }
             } else if (subencoding & 0x01) {  // Raw
                 let pixels = tw * th;
-                let data = sock.rQshiftBytes(pixels * 4);
+                let data = sock.rQshiftBytes(pixels * 4, false);
                 // Max sure the image is fully opaque
                 for (let i = 0;i <  pixels;i++) {
                     data[i * 4 + 3] = 255;
index 5f5cc26549e4c4a89dbf7e29d3837e12adceabc6..feb2aeb6c9dc9ffd08cbb83ffd5836c6c49602c9 100644 (file)
@@ -124,7 +124,7 @@ export default class JPEGDecoder {
                 if (sock.rQwait("JPEG", length-2+extra, 4)) {
                     return null;
                 }
-                let data = sock.rQpeekBytes(length-2+extra);
+                let data = sock.rQpeekBytes(length-2+extra, false);
                 if (data.at(-2) === 0xFF && data.at(-1) !== 0x00 &&
                     !(data.at(-1) >= 0xD0 && data.at(-1) <= 0xD7)) {
                     extra -= 2;
@@ -139,7 +139,7 @@ export default class JPEGDecoder {
         segment[1] = type;
         segment[2] = length >> 8;
         segment[3] = length;
-        segment.set(sock.rQshiftBytes(length-2+extra), 4);
+        segment.set(sock.rQshiftBytes(length-2+extra, false), 4);
 
         return segment;
     }
index 488ac1af6c6492fdaebbd51b048835ea0726cc2a..3c1661425b0b0e6fd6b47d565abb00827a2ff271 100644 (file)
@@ -31,7 +31,7 @@ export default class RawDecoder {
 
             const curY = y + (height - this._lines);
 
-            let data = sock.rQshiftBytes(bytesPerLine);
+            let data = sock.rQshiftBytes(bytesPerLine, false);
 
             // Convert data if needed
             if (depth == 8) {
index 5eaed5452ef649ef3462e1ab6de4765ed018cce8..45622080f0f5859c523f9d908a6e3c01c0892933 100644 (file)
@@ -312,7 +312,7 @@ export default class TightDecoder {
             return null;
         }
 
-        let data = sock.rQshiftBytes(this._len);
+        let data = sock.rQshiftBytes(this._len, false);
         this._len = 0;
 
         return data;
index 97fbd58e7a1c113fb3e5053135e5130dbf9f9dca..49128e7983e959169e898489b74853c578872d3e 100644 (file)
@@ -32,7 +32,7 @@ export default class ZRLEDecoder {
             return false;
         }
 
-        const data = sock.rQshiftBytes(this._length);
+        const data = sock.rQshiftBytes(this._length, false);
 
         this._inflator.setInput(data);
 
index b6891329e67ca4c9a9483eff7f50b5ddba28356c..7cd87091f2f184640b3e2b0adb1aaba4c3f7a022 100644 (file)
@@ -128,15 +128,19 @@ export default class Websock {
         let str = "";
         // Handle large arrays in steps to avoid long strings on the stack
         for (let i = 0; i < len; i += 4096) {
-            let part = this.rQshiftBytes(Math.min(4096, len - i));
+            let part = this.rQshiftBytes(Math.min(4096, len - i), false);
             str += String.fromCharCode.apply(null, part);
         }
         return str;
     }
 
-    rQshiftBytes(len) {
+    rQshiftBytes(len, copy=true) {
         this._rQi += len;
-        return new Uint8Array(this._rQ.buffer, this._rQi - len, len);
+        if (copy) {
+            return this._rQ.slice(this._rQi - len, this._rQi);
+        } else {
+            return this._rQ.subarray(this._rQi - len, this._rQi);
+        }
     }
 
     rQshiftTo(target, len) {
@@ -145,8 +149,12 @@ export default class Websock {
         this._rQi += len;
     }
 
-    rQpeekBytes(len) {
-        return new Uint8Array(this._rQ.buffer, this._rQi, len);
+    rQpeekBytes(len, copy=true) {
+        if (copy) {
+            return this._rQ.slice(this._rQi, this._rQi + len);
+        } else {
+            return this._rQ.subarray(this._rQi, this._rQi + len);
+        }
     }
 
     // Check to see if we must wait for 'num' bytes (default to FBU.bytes)
index 2034bd6e70017e1372e18f0c0ff439f5a810910f..d501021a3813dd9d052fb1e842393853374f69d9 100644 (file)
@@ -101,6 +101,12 @@ describe('Websock', function () {
                 expect(shifted).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, befRQi, 3));
                 expect(sock._rQlen - sock._rQi).to.equal(befLen - 3);
             });
+            it('should return a shared array if requested', function () {
+                const befRQi = sock._rQi;
+                const shifted = sock.rQshiftBytes(3, false);
+                expect(shifted).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, befRQi, 3));
+                expect(shifted.buffer.byteLength).to.not.equal(shifted.length);
+            });
         });
 
         describe('rQpeekBytes', function () {
@@ -124,6 +130,12 @@ describe('Websock', function () {
                 sock._rQi = 1;
                 expect(sock.rQpeekBytes(2)).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1, 2));
             });
+
+            it('should return a shared array if requested', function () {
+                const sl = sock.rQpeekBytes(2, false);
+                expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 0, 2));
+                expect(sl.buffer.byteLength).to.not.equal(sl.length);
+            });
         });
 
         describe('rQwait', function () {