From adda9366c11f736c77dcf8f765e6c4ab58b217e4 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 21 Aug 2019 12:09:35 +0200 Subject: [PATCH] feat: assume HTTP when multiaddr ends with /tcp (#7) This makes multiaddrs ending with `/tcp/8080` to default to HTTP unless an explicit assumeHttp: false is passed. We also skip default ports for HTTP and HTTPS in the URL. Motivation: https://github.com/ipfs/js-ipfs/pull/2358#issue-307463029 License: MIT Signed-off-by: Marcin Rataj --- README.md | 9 +++++++++ index.js | 23 +++++++++++++++++++---- test.js | 39 ++++++++++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6356a9b..5e3ec2d 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,19 @@ const toUri = require('multiaddr-to-uri') console.log(toUri('/dnsaddr/protocol.ai/https')) // -> https://protocol.ai + +console.log(toUri('/ip4/127.0.0.1/tcp/8080')) +// -> http://127.0.0.1:8080 + +console.log(toUri('/ip4/127.0.0.1/tcp/8080', { assumeHttp: false })) +// -> tcp://127.0.0.1:8080 ``` Note: +* When `/tcp` is the last (terminating) protocol HTTP is assumed by default (implicit `assumeHttp: true`) + * this means produced URIs will start with `http://` instead of `tcp://` + * passing `{ assumeHttp: false }` disables this behavior * Might be lossy - e.g. a DNSv6 multiaddr * Can throw if the passed multiaddr: * is not a valid multiaddr diff --git a/index.js b/index.js index 623e869..495bd00 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,20 @@ const Multiaddr = require('multiaddr') + const reduceValue = (_, v) => v +const tcpUri = (str, port, parts, opts) => { + // return tcp when explicitly requested + if (opts && opts.assumeHttp === false) return `tcp://${str}:${port}` + // check if tcp is the last protocol in multiaddr + let protocol = 'tcp' + let explicitPort = `:${port}` + const last = parts[parts.length - 1] + if (last.protocol === 'tcp') { + // assume http and produce clean urls + protocol = port === 443 ? 'https' : 'http' + explicitPort = port === 443 || port === 80 ? '' : explicitPort + } + return `${protocol}://${str}${explicitPort}` +} const Reducers = { ip4: reduceValue, @@ -8,10 +23,10 @@ const Reducers = { ? content : `[${content}]` ), - tcp: (str, content, i, parts) => ( + tcp: (str, content, i, parts, opts) => ( parts.some(p => ['http', 'https', 'ws', 'wss'].includes(p.protocol)) ? `${str}:${content}` - : `tcp://${str}:${content}` + : tcpUri(str, content, parts, opts) ), udp: (str, content) => `udp://${str}:${content}`, dnsaddr: reduceValue, @@ -28,7 +43,7 @@ const Reducers = { 'p2p-webrtc-direct': str => `${str}/p2p-webrtc-direct` } -module.exports = (multiaddr) => ( +module.exports = (multiaddr, opts) => ( Multiaddr(multiaddr) .stringTuples() .map(tuple => ({ @@ -38,6 +53,6 @@ module.exports = (multiaddr) => ( .reduce((str, part, i, parts) => { const reduce = Reducers[part.protocol] if (!reduce) throw new Error(`Unsupported protocol ${part.protocol}`) - return reduce(str, part.content, i, parts) + return reduce(str, part.content, i, parts, opts) }, '') ) diff --git a/test.js b/test.js index cdcd69d..4f3ed71 100644 --- a/test.js +++ b/test.js @@ -7,19 +7,14 @@ test('should convert multiaddr to URI', (t) => { ['/ip4/127.0.0.1/http', 'http://127.0.0.1'], ['/ip6/fc00::', 'fc00::'], ['/ip6/fc00::/http', 'http://[fc00::]'], - ['/ip4/0.0.7.6/tcp/1234', 'tcp://0.0.7.6:1234'], ['/ip4/0.0.7.6/tcp/1234/http', 'http://0.0.7.6:1234'], ['/ip4/0.0.7.6/tcp/1234/https', 'https://0.0.7.6:1234'], - ['/ip6/::/tcp/0', 'tcp://[::]:0'], ['/ip4/0.0.7.6/udp/1234', 'udp://0.0.7.6:1234'], ['/ip6/::/udp/0', 'udp://[::]:0'], ['/dnsaddr/ipfs.io', 'ipfs.io'], ['/dns4/ipfs.io', 'ipfs.io'], ['/dns4/libp2p.io', 'libp2p.io'], ['/dns6/protocol.ai', 'protocol.ai'], - ['/dns4/protocol.ai/tcp/80', 'tcp://protocol.ai:80'], - ['/dns6/protocol.ai/tcp/80', 'tcp://protocol.ai:80'], - ['/dnsaddr/protocol.ai/tcp/80', 'tcp://protocol.ai:80'], ['/dnsaddr/protocol.ai/tcp/80/http', 'http://protocol.ai:80'], ['/dnsaddr/protocol.ai/tcp/80/https', 'https://protocol.ai:80'], ['/dnsaddr/ipfs.io/ws', 'ws://ipfs.io'], @@ -83,6 +78,40 @@ test('should convert multiaddr to URI', (t) => { data.forEach(d => t.is(toUri(d[0]), d[1])) }) +test('should convert multiaddr to http(s):// URI when implicit { assumeHttp: true }', (t) => { + const data = [ + ['/ip4/0.0.7.6/tcp/1234', 'http://0.0.7.6:1234'], + ['/ip6/::/tcp/0', 'http://[::]:0'], + ['/dns4/protocol.ai/tcp/80', 'http://protocol.ai'], + ['/dns6/protocol.ai/tcp/80', 'http://protocol.ai'], + ['/dns4/protocol.ai/tcp/8080', 'http://protocol.ai:8080'], + ['/dns6/protocol.ai/tcp/8080', 'http://protocol.ai:8080'], + ['/dns4/protocol.ai/tcp/443', 'https://protocol.ai'], + ['/dns6/protocol.ai/tcp/443', 'https://protocol.ai'], + ['/dnsaddr/protocol.ai/tcp/80', 'http://protocol.ai'], + ['/dnsaddr/protocol.ai/tcp/443', 'https://protocol.ai'], + ['/dnsaddr/protocol.ai/tcp/8080', 'http://protocol.ai:8080'] + ] + data.forEach(d => t.is(toUri(d[0]), d[1])) +}) + +test('should convert multiaddr to tcp:// URI when explicit { assumeHttp: false }', (t) => { + const data = [ + ['/ip4/0.0.7.6/tcp/1234', 'tcp://0.0.7.6:1234'], + ['/ip6/::/tcp/0', 'tcp://[::]:0'], + ['/dns4/protocol.ai/tcp/80', 'tcp://protocol.ai:80'], + ['/dns6/protocol.ai/tcp/80', 'tcp://protocol.ai:80'], + ['/dns4/protocol.ai/tcp/8080', 'tcp://protocol.ai:8080'], + ['/dns6/protocol.ai/tcp/8080', 'tcp://protocol.ai:8080'], + ['/dns4/protocol.ai/tcp/443', 'tcp://protocol.ai:443'], + ['/dns6/protocol.ai/tcp/443', 'tcp://protocol.ai:443'], + ['/dnsaddr/protocol.ai/tcp/80', 'tcp://protocol.ai:80'], + ['/dnsaddr/protocol.ai/tcp/443', 'tcp://protocol.ai:443'], + ['/dnsaddr/protocol.ai/tcp/8080', 'tcp://protocol.ai:8080'] + ] + data.forEach(d => t.is(toUri(d[0], { assumeHttp: false }), d[1])) +}) + test('should throw for unsupported protocol', (t) => { t.throws(() => toUri('/quic')) })