From a2825ace27d51fa1d6421a995cc38af346b2c03c Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Sun, 1 Nov 2020 01:14:18 -0600 Subject: [PATCH] fix: prevent device node leaks and stale urlHandlers --- .../lib/ag-solo/vats/vat-http.js | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/packages/cosmic-swingset/lib/ag-solo/vats/vat-http.js b/packages/cosmic-swingset/lib/ag-solo/vats/vat-http.js index e87af73aa66..ae4d40de1d4 100644 --- a/packages/cosmic-swingset/lib/ag-solo/vats/vat-http.js +++ b/packages/cosmic-swingset/lib/ag-solo/vats/vat-http.js @@ -52,7 +52,8 @@ export function buildRootObject(vatPowers) { obj || JSON.parse(JSON.stringify(obj)), ); - const registeredURLHandlers = new Map(); + // Map an URL only to its latest handler. + const urlToHandler = new Map(); async function registerURLHandler(handler, url) { const fallback = await E(handler) @@ -66,12 +67,7 @@ export function buildRootObject(vatPowers) { .catch(_e => undefined), fallback, ); - let reg = registeredURLHandlers.get(url); - if (!reg) { - reg = []; - registeredURLHandlers.set(url, reg); - } - reg.push(commandHandler); + urlToHandler.set(url, commandHandler); } return harden({ @@ -145,12 +141,15 @@ export function buildRootObject(vatPowers) { // devices.command invokes our inbound() because we passed to // registerInboundHandler() async inbound(count, rawObj) { + // Launder the data, since the command device tends to pass device nodes + // when there are empty objects, which screw things up for us. + const obj = JSON.parse(JSON.stringify(rawObj)); console.debug( `vat-http.inbound (from browser) ${count}`, - JSON.stringify(rawObj, undefined, 2), + JSON.stringify(obj, undefined, 2), ); - const { type, meta: rawMeta = {} } = rawObj || {}; + const { type, meta: rawMeta = {} } = obj || {}; const { url = '/private/repl', channelID: rawChannelID, @@ -168,9 +167,6 @@ export function buildRootObject(vatPowers) { channelHandleToId.delete(channelHandle); } - const obj = { - ...rawObj, - }; delete obj.meta; const meta = { @@ -179,19 +175,12 @@ export function buildRootObject(vatPowers) { }; delete meta.channelID; - const urlHandlers = registeredURLHandlers.get(url); - if (urlHandlers) { - // todo fixme avoid the loop - // For now, go from the end to beginning so that handlers - // override. - for (let i = urlHandlers.length - 1; i >= 0; i -= 1) { - // eslint-disable-next-line no-await-in-loop - const res = await E(urlHandlers[i])[dispatcher](obj, meta); - - if (res) { - sendResponse(count, false, res); - return; - } + const urlHandler = urlToHandler.get(url); + if (urlHandler) { + const res = await E(urlHandler)[dispatcher](obj, meta); + if (res) { + sendResponse(count, false, res); + return; } }