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

feat: add HTTP Gateway support for /ipns/ paths #2020

Merged
merged 8 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@
"ipfs-block": "~0.8.1",
"ipfs-block-service": "~0.15.1",
"ipfs-http-client": "^32.0.1",
"ipfs-http-response": "~0.3.0",
"ipfs-mfs": "~0.11.4",
"ipfs-http-response": "~0.3.1",
"ipfs-mfs": "~0.11.5",
"ipfs-multipart": "~0.1.0",
"ipfs-repo": "~0.26.6",
"ipfs-unixfs": "~0.1.16",
Expand Down
4 changes: 2 additions & 2 deletions src/http/api/routes/webui.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ const resources = require('../../gateway/resources')
module.exports = [
{
method: '*',
path: '/ipfs/{cid*}',
path: '/ipfs/{immutableId*}',
options: {
pre: [
{ method: resources.gateway.checkCID, assign: 'args' }
{ method: resources.gateway.checkImmutableId, assign: 'args' }
]
},
handler: resources.gateway.handler
Expand Down
29 changes: 23 additions & 6 deletions src/http/gateway/resources/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ function detectContentType (ref, chunk) {
return mime.contentType(mimeType)
}

async function resolveIpns (ref, ipfs) {
const [ root ] = PathUtils.splitPath(ref)
const immutableRoot = await ipfs.name.resolve(root, { recursive: true })
return ref.replace(`/ipns/${root}`, PathUtils.removeTrailingSlash(immutableRoot))
}
lidel marked this conversation as resolved.
Show resolved Hide resolved

// Enable streaming of compressed payload
// https://github.com/hapijs/hapi/issues/3599
class ResponseStream extends PassThrough {
Expand All @@ -45,29 +51,40 @@ class ResponseStream extends PassThrough {
}

module.exports = {
checkCID (request, h) {
if (!request.params.cid) {
checkImmutableId (request, h) {
lidel marked this conversation as resolved.
Show resolved Hide resolved
if (!request.params.immutableId) {
throw Boom.badRequest('Path Resolve error: path must contain at least one component')
}

return { ref: `/ipfs/${request.params.cid}` }
return { ref: `/ipfs/${request.params.immutableId}` }
},
checkMutableId (request, h) {
lidel marked this conversation as resolved.
Show resolved Hide resolved
if (!request.params.mutableId) {
throw Boom.badRequest('Path Resolve error: path must contain at least one component')
}
return { ref: `/ipns/${request.params.mutableId}` }
},

async handler (request, h) {
const { ref } = request.pre.args
const { ipfs } = request.server.app

// The resolver from ipfs-http-response supports only immutable /ipfs/ for now,
// so we convert /ipns/ to /ipfs/ before passing it to the resolver ¯\_(ツ)_/¯
// This can be removed if a solution proposed in
// https://github.com/ipfs/js-ipfs-http-response/issues/22 lands upstream
const immutableRef = ref.startsWith('/ipns/') ? await resolveIpns(ref, ipfs) : ref

let data
try {
data = await resolver.cid(ipfs, ref)
data = await resolver.cid(ipfs, immutableRef)
lidel marked this conversation as resolved.
Show resolved Hide resolved
} catch (err) {
const errorToString = err.toString()
log.error('err: ', errorToString, ' fileName: ', err.fileName)

// switch case with true feels so wrong.
switch (true) {
case (errorToString === 'Error: This dag node is a directory'):
data = await resolver.directory(ipfs, ref, err.cid)
data = await resolver.directory(ipfs, immutableRef, err.cid)
lidel marked this conversation as resolved.
Show resolved Hide resolved

if (typeof data === 'string') {
// no index file found
Expand Down
46 changes: 32 additions & 14 deletions src/http/gateway/routes/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,37 @@

const resources = require('../resources')

module.exports = {
method: '*',
path: '/ipfs/{cid*}',
options: {
handler: resources.gateway.handler,
pre: [
{ method: resources.gateway.checkCID, assign: 'args' }
],
response: {
ranges: false // disable built-in support, we do it manually
},
ext: {
onPostHandler: { method: resources.gateway.afterHandler }
module.exports = [
{
method: '*',
path: '/ipfs/{immutableId*}',
lidel marked this conversation as resolved.
Show resolved Hide resolved
options: {
handler: resources.gateway.handler,
pre: [
{ method: resources.gateway.checkImmutableId, assign: 'args' }
],
response: {
ranges: false // disable built-in support, we do it manually
},
ext: {
onPostHandler: { method: resources.gateway.afterHandler }
}
}
},
{
method: '*',
path: '/ipns/{mutableId*}',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should define what we should call this id, libp2p-key, ipns-key-id, even ipns-cid (content been the hash of the pubkey) and we should PR to the spec https://github.com/ipfs/specs/tree/master/naming this new name.

Copy link
Member Author

@lidel lidel Jul 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have libp2p-key multicodec now for presenting IPNS names as base32 CIDv1, but it can also be FQDN with DNSLink, so I renamed it to libp2pKeyOrFqdn.

I did not touch mentioned spec as /ipns/base32(<HASH>) mentioned there has direct implication on how things are implemented: https://github.com/ipfs/js-ipns/blob/v0.5.2/src/index.js#L214 (IPNS does not use <libp2p-key-in-cidv1b32> but raw concatenation of /ipns/ and key buffer, and now they move to just buffer)

options: {
handler: resources.gateway.handler,
pre: [
{ method: resources.gateway.checkMutableId, assign: 'args' }
],
response: {
ranges: false // disable built-in support, we do it manually
},
ext: {
onPostHandler: { method: resources.gateway.afterHandler }
}
}
}
}
]
2 changes: 1 addition & 1 deletion src/http/gateway/routes/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
'use strict'

module.exports = [require('./gateway')]
module.exports = [...require('./gateway')]
lidel marked this conversation as resolved.
Show resolved Hide resolved