diff --git a/indexer/lib/vendored/multiaddr.js b/indexer/lib/vendored/multiaddr.js index 217078c..da80592 100644 --- a/indexer/lib/vendored/multiaddr.js +++ b/indexer/lib/vendored/multiaddr.js @@ -6,13 +6,31 @@ * @returns {string} Parsed URI, e.g. `http://127.0.0.1:80` */ export function multiaddrToHttpUrl (addr) { - const [, hostType, hostValue, ipProtocol, port, scheme, ...rest] = addr.split('/') + const [multiAddr, httpPathMultiAddr] = addr.split('/http-path') + const [, hostType, hostValue, ...multiAddrParts] = multiAddr.split('/') + let scheme, path, rest, port + if (addr.includes('/http-path')) { + [scheme, ...rest] = multiAddrParts + try { + // Remove leading slash and parse URI-encoded path + // See https://github.com/multiformats/multiaddr/blob/cab92e8e6da2e70c5f1b8aa59976e71e6922b392/protocols/http-path.md#usage + path = decodeURIComponent(httpPathMultiAddr.substring(1)) + } catch (err) { + throw Object.assign( + new Error(`Cannot parse "${addr}": unsupported http path`, { cause: err }), + { code: 'INVALID_HTTP_PATH' } + ) + } + } else { + let ipProtocol + ;[ipProtocol, port, scheme, ...rest] = multiAddrParts - if (ipProtocol !== 'tcp') { - throw Object.assign( - new Error(`Cannot parse "${addr}": unsupported protocol "${ipProtocol}"`), - { code: 'UNSUPPORTED_MULTIADDR_PROTO' } - ) + if (ipProtocol !== 'tcp') { + throw Object.assign( + new Error(`Cannot parse "${addr}": unsupported protocol "${ipProtocol}"`), + { code: 'UNSUPPORTED_MULTIADDR_PROTO' } + ) + } } if (scheme !== 'http' && scheme !== 'https') { @@ -29,7 +47,10 @@ export function multiaddrToHttpUrl (addr) { ) } - return `${scheme}://${getUriHost(hostType, hostValue)}${getUriPort(scheme, port)}` + let url = `${scheme}://${getUriHost(hostType, hostValue)}` + if (port) url += getUriPort(scheme, port) + if (path) url += path + return url } function getUriHost (hostType, hostValue) { diff --git a/indexer/test/advertisement-walker.test.js b/indexer/test/advertisement-walker.test.js index 1b9f7b8..3056b8a 100644 --- a/indexer/test/advertisement-walker.test.js +++ b/indexer/test/advertisement-walker.test.js @@ -35,7 +35,6 @@ const knownAdvertisement = { payloadCid: 'bafkreigrnnl64xuevvkhknbhrcqzbdvvmqnchp7ae2a4ulninsjoc5svoq', pieceCid: 'baga6ea4seaqlwzed5tgjtyhrugjziutzthx2wrympvsuqhfngwdwqzvosuchmja' } - describe('processNextAdvertisement', () => { it('ignores non-HTTP(s) addresses and explains the problem in the status', async () => { /** @type {ProviderInfo} */ @@ -58,6 +57,26 @@ describe('processNextAdvertisement', () => { }) }) + it('ignores malformed http-path addresses and explains the problem in the status', async () => { + /** @type {ProviderInfo} */ + const providerInfo = { + providerAddress: '/dns/meridian.space/http/http-path/invalid%path', + lastAdvertisementCID: 'baguqeeraTEST' + } + + const result = await processNextAdvertisement({ + providerId, + providerInfo, + walkerState: undefined + }) + assert.deepStrictEqual(result, { + finished: true, + newState: { + status: 'Index provider advertises over an unsupported protocol: /dns/meridian.space/http/http-path/invalid%path' + } + }) + }) + it('handles a new index provider not seen before', async () => { /** @type {ProviderInfo} */ const providerInfo = {