From 073737c8acc51c4a9366ece74afd134e11c70d35 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 4 Sep 2020 16:16:44 +0200 Subject: [PATCH] Handle empty rects from the server These are very pointless for the server to send, but not a violation of the protocol so we need to be able to handle them. We've seen this happen in real world scenarios a few times. --- kasmweb/core/decoders/copyrect.js | 5 +++ kasmweb/core/decoders/tight.js | 8 +++++ kasmweb/tests/test.copyrect.js | 17 ++++++++++ kasmweb/tests/test.hextile.js | 17 ++++++++++ kasmweb/tests/test.raw.js | 34 +++++++++++++++++++ kasmweb/tests/test.rre.js | 17 ++++++++++ kasmweb/tests/test.tight.js | 55 +++++++++++++++++++++++++++++++ 7 files changed, 153 insertions(+) diff --git a/kasmweb/core/decoders/copyrect.js b/kasmweb/core/decoders/copyrect.js index 0e0536a..9e6391a 100644 --- a/kasmweb/core/decoders/copyrect.js +++ b/kasmweb/core/decoders/copyrect.js @@ -15,6 +15,11 @@ export default class CopyRectDecoder { let deltaX = sock.rQshift16(); let deltaY = sock.rQshift16(); + + if ((width === 0) || (height === 0)) { + return true; + } + display.copyImage(deltaX, deltaY, x, y, width, height); return true; diff --git a/kasmweb/core/decoders/tight.js b/kasmweb/core/decoders/tight.js index be9f1cc..dfe90f2 100644 --- a/kasmweb/core/decoders/tight.js +++ b/kasmweb/core/decoders/tight.js @@ -162,6 +162,10 @@ export default class TightDecoder { const uncompressedSize = width * height * 3; let data; + if (uncompressedSize === 0) { + return true; + } + if (uncompressedSize < 12) { if (sock.rQwait("TIGHT", uncompressedSize)) { return false; @@ -217,6 +221,10 @@ export default class TightDecoder { let data; + if (uncompressedSize === 0) { + return true; + } + if (uncompressedSize < 12) { if (sock.rQwait("TIGHT", uncompressedSize)) { return false; diff --git a/kasmweb/tests/test.copyrect.js b/kasmweb/tests/test.copyrect.js index fcf4219..afb778f 100644 --- a/kasmweb/tests/test.copyrect.js +++ b/kasmweb/tests/test.copyrect.js @@ -57,4 +57,21 @@ describe('CopyRect Decoder', function () { expect(display).to.have.displayed(targetData); }); + + it('should handle empty rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [0x00, 0x00, 0x00, 0x00], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); }); diff --git a/kasmweb/tests/test.hextile.js b/kasmweb/tests/test.hextile.js index 7c97527..bac415f 100644 --- a/kasmweb/tests/test.hextile.js +++ b/kasmweb/tests/test.hextile.js @@ -206,4 +206,21 @@ describe('Hextile Decoder', function () { let data = [45]; // an invalid subencoding expect(() => testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24)).to.throw(); }); + + it('should handle empty rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); }); diff --git a/kasmweb/tests/test.raw.js b/kasmweb/tests/test.raw.js index b42e4f3..4830bbb 100644 --- a/kasmweb/tests/test.raw.js +++ b/kasmweb/tests/test.raw.js @@ -86,4 +86,38 @@ describe('Raw Decoder', function () { expect(display).to.have.displayed(targetData); }); + + it('should handle empty rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty rects in low colour mode', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [], display, 8); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); }); diff --git a/kasmweb/tests/test.rre.js b/kasmweb/tests/test.rre.js index 78b5eaa..583cd5a 100644 --- a/kasmweb/tests/test.rre.js +++ b/kasmweb/tests/test.rre.js @@ -81,4 +81,21 @@ describe('RRE Decoder', function () { expect(display).to.have.displayed(targetData); }); + + it('should handle empty rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [ 0x00, 0xff, 0xff, 0xff, 0xff ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); }); diff --git a/kasmweb/tests/test.tight.js b/kasmweb/tests/test.tight.js index 10ef971..d89cf57 100644 --- a/kasmweb/tests/test.tight.js +++ b/kasmweb/tests/test.tight.js @@ -210,6 +210,61 @@ describe('Tight Decoder', function () { // Not implemented yet }); + it('should handle empty copy rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [ 0x00 ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty palette rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, + [ 0x40, 0x01, 0x01, + 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty fill rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, + [ 0x80, 0xff, 0xff, 0xff ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + it('should handle JPEG rects', function (done) { let data = [ // Control bytes