From 1e321c64e2b0f854d061f973ed255d54e5f740ba Mon Sep 17 00:00:00 2001 From: Dirk Steinmetz Date: Sun, 13 Mar 2022 19:58:03 +0100 Subject: [PATCH] tcp: Fix reading into large buffers Recent versions of Thunderbird limit the amount of data cached in a socket for reading. Waiting until enough data is available to fill a large buffer thus might cause the application to hang. This commit thus alters the behavior of readFully to read out all available data from the socket immediately, filling the given buffer in multiple steps if required. --- experiments/tcp/child.js | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/experiments/tcp/child.js b/experiments/tcp/child.js index a66dd88..6dc3649 100644 --- a/experiments/tcp/child.js +++ b/experiments/tcp/child.js @@ -62,8 +62,40 @@ var ex_tcp = class extends ExtensionCommon.ExtensionAPI { // Completely fills the given ArrayBuffer with read data const readFully = async function(buffer) { - const remaining = buffer.byteLength; - while (socketIn.available() < remaining) { + let offset = 0; + let remaining = buffer.byteLength; + while (true) { + let bytesToRead = socketInBinary.available(); + if (bytesToRead > 0) { + if (bytesToRead > remaining) { + bytesToRead = remaining; + } + let read; + if (offset == 0) { + read = socketInBinary.readArrayBuffer(bytesToRead, buffer); + } else { + // There is no option to read to an offset, so we need to go + // through a temporary buffer living in the same privilege + // level. + let tempArray = new context.cloneScope.Uint8Array( + new context.cloneScope.ArrayBuffer(bytesToRead)); + read = socketInBinary.readArrayBuffer(bytesToRead, + tempArray.buffer); + if (read > 0) { + let bufferArray = new context.cloneScope.Uint8Array(buffer, + offset, bytesToRead); + bufferArray.set(tempArray); + } + } + if (read != bytesToRead) { + throw Error("Could not read available bytes into buffer"); + } + remaining -= read; + if (remaining <= 0) { + break; + } + offset += read; + } await new Promise(resolve => socketIn.asyncWait({ QueryInterface: ChromeUtils.generateQI([ Ci.nsIInputStreamCallback]), @@ -72,10 +104,6 @@ var ex_tcp = class extends ExtensionCommon.ExtensionAPI { } }, 0, remaining, tmService.mainThreadEventTarget)); } - if (socketInBinary.readArrayBuffer(remaining, buffer) - !== remaining) { - throw new Error("Could not read available bytes into buffer"); - } }; // Writes the content of the given ArrayBuffer -- 2.35.1