aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-05-31 18:19:53 -0400
committertoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-05-31 18:22:46 -0400
commit13b59dacb2cd8f907eaba6b97f927b72f02fe672 (patch)
tree4212842c599cea507b96fd8b2bb10163d2607236
parentd0dcff765f740bf6f0f6523b09cb8b21eb85cd93 (diff)
Limit action port message size (#587)
* Add onDisconnect handler * Update how error is posted * Update action ports to send long messages in fragments * Remove ack timer * Move message destructuring into try block
-rw-r--r--ext/bg/js/backend.js47
-rw-r--r--ext/mixed/js/api.js26
2 files changed, 46 insertions, 27 deletions
diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js
index 20d31efc..0af64377 100644
--- a/ext/bg/js/backend.js
+++ b/ext/bg/js/backend.js
@@ -805,6 +805,7 @@ class Backend {
_createActionListenerPort(port, sender, handlers) {
let hasStarted = false;
+ let messageString = '';
const onProgress = (...data) => {
try {
@@ -815,12 +816,34 @@ class Backend {
}
};
- const onMessage = async ({action, params}) => {
+ const onMessage = (message) => {
if (hasStarted) { return; }
- hasStarted = true;
- port.onMessage.removeListener(onMessage);
try {
+ const {action, data} = message;
+ switch (action) {
+ case 'fragment':
+ messageString += data;
+ break;
+ case 'invoke':
+ {
+ hasStarted = true;
+ port.onMessage.removeListener(onMessage);
+
+ const messageData = JSON.parse(messageString);
+ messageString = null;
+ onMessageComplete(messageData);
+ }
+ break;
+ }
+ } catch (e) {
+ cleanup(e);
+ }
+ };
+
+ const onMessageComplete = async (message) => {
+ try {
+ const {action, params} = message;
port.postMessage({type: 'ack'});
const messageHandler = handlers.get(action);
@@ -837,25 +860,29 @@ class Backend {
const result = async ? await promiseOrResult : promiseOrResult;
port.postMessage({type: 'complete', data: result});
} catch (e) {
- if (port !== null) {
- port.postMessage({type: 'error', data: errorToJson(e)});
- }
- cleanup();
+ cleanup(e);
}
};
- const cleanup = () => {
+ const onDisconnect = () => {
+ cleanup(null);
+ };
+
+ const cleanup = (error) => {
if (port === null) { return; }
+ if (error !== null) {
+ port.postMessage({type: 'error', data: errorToJson(error)});
+ }
if (!hasStarted) {
port.onMessage.removeListener(onMessage);
}
- port.onDisconnect.removeListener(cleanup);
+ port.onDisconnect.removeListener(onDisconnect);
port = null;
handlers = null;
};
port.onMessage.addListener(onMessage);
- port.onDisconnect.addListener(cleanup);
+ port.onDisconnect.addListener(onDisconnect);
}
_getErrorLevelValue(errorLevel) {
diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js
index 0bc91759..d2be12aa 100644
--- a/ext/mixed/js/api.js
+++ b/ext/mixed/js/api.js
@@ -204,7 +204,6 @@ function _apiCreateActionPort(timeout=5000) {
function _apiInvokeWithProgress(action, params, onProgress, timeout=5000) {
return new Promise((resolve, reject) => {
- let timer = null;
let port = null;
if (typeof onProgress !== 'function') {
@@ -213,12 +212,6 @@ function _apiInvokeWithProgress(action, params, onProgress, timeout=5000) {
const onMessage = (message) => {
switch (message.type) {
- case 'ack':
- if (timer !== null) {
- clearTimeout(timer);
- timer = null;
- }
- break;
case 'progress':
try {
onProgress(...message.data);
@@ -243,10 +236,6 @@ function _apiInvokeWithProgress(action, params, onProgress, timeout=5000) {
};
const cleanup = () => {
- if (timer !== null) {
- clearTimeout(timer);
- timer = null;
- }
if (port !== null) {
port.onMessage.removeListener(onMessage);
port.onDisconnect.removeListener(onDisconnect);
@@ -256,17 +245,20 @@ function _apiInvokeWithProgress(action, params, onProgress, timeout=5000) {
onProgress = null;
};
- timer = setTimeout(() => {
- cleanup();
- reject(new Error('Timeout'));
- }, timeout);
-
(async () => {
try {
port = await _apiCreateActionPort(timeout);
port.onMessage.addListener(onMessage);
port.onDisconnect.addListener(onDisconnect);
- port.postMessage({action, params});
+
+ // Chrome has a maximum message size that can be sent, so longer messages must be fragmented.
+ const messageString = JSON.stringify({action, params});
+ const fragmentSize = 1e7; // 10 MB
+ for (let i = 0, ii = messageString.length; i < ii; i += fragmentSize) {
+ const data = messageString.substring(i, i + fragmentSize);
+ port.postMessage({action: 'fragment', data});
+ }
+ port.postMessage({action: 'invoke'});
} catch (e) {
cleanup();
reject(e);