Skip to content
This repository has been archived by the owner on Feb 25, 2023. It is now read-only.

Commit

Permalink
Limit action port message size (#587)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
toasted-nutbread committed May 31, 2020
1 parent d0dcff7 commit 13b59da
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 27 deletions.
47 changes: 37 additions & 10 deletions ext/bg/js/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ class Backend {

_createActionListenerPort(port, sender, handlers) {
let hasStarted = false;
let messageString = '';

const onProgress = (...data) => {
try {
Expand All @@ -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);
Expand All @@ -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) {
Expand Down
26 changes: 9 additions & 17 deletions ext/mixed/js/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 13b59da

Please sign in to comment.