diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-05-31 18:17:12 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-31 18:17:12 -0400 | 
| commit | 2c58b1c1091355e5e4f2a2c20d96051863549b8d (patch) | |
| tree | 83fc2188e5dab2cdaf354fc7a2634dcc1a218f36 /ext | |
| parent | cfd3a1ec3a5140e539a7fcc7d83656254c97b4d4 (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
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/js/backend.js | 47 | ||||
| -rw-r--r-- | ext/mixed/js/api.js | 26 | 
2 files changed, 46 insertions, 27 deletions
| diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 08ce82a2..5eb7982d 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -861,6 +861,7 @@ class Backend {      _createActionListenerPort(port, sender, handlers) {          let hasStarted = false; +        let messageString = '';          const onProgress = (...data) => {              try { @@ -871,12 +872,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); @@ -893,25 +916,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 075ea545..5e3195d6 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -236,7 +236,6 @@ const api = (() => {          _invokeWithProgress(action, params, onProgress, timeout=5000) {              return new Promise((resolve, reject) => { -                let timer = null;                  let port = null;                  if (typeof onProgress !== 'function') { @@ -245,12 +244,6 @@ const api = (() => {                  const onMessage = (message) => {                      switch (message.type) { -                        case 'ack': -                            if (timer !== null) { -                                clearTimeout(timer); -                                timer = null; -                            } -                            break;                          case 'progress':                              try {                                  onProgress(...message.data); @@ -275,10 +268,6 @@ const api = (() => {                  };                  const cleanup = () => { -                    if (timer !== null) { -                        clearTimeout(timer); -                        timer = null; -                    }                      if (port !== null) {                          port.onMessage.removeListener(onMessage);                          port.onDisconnect.removeListener(onDisconnect); @@ -288,17 +277,20 @@ const api = (() => {                      onProgress = null;                  }; -                timer = setTimeout(() => { -                    cleanup(); -                    reject(new Error('Timeout')); -                }, timeout); -                  (async () => {                      try {                          port = await this._createActionPort(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); |