UNPKG

@helia/verified-fetch

Version:

A fetch-like API for obtaining verified & trustless IPFS content on the web

78 lines 3.75 kB
import * as ipldDagCbor from '@ipld/dag-cbor'; import * as ipldDagJson from '@ipld/dag-json'; import { dagCborToSafeJSON } from '../utils/dag-cbor-to-safe-json.js'; import { setIpfsRoots } from '../utils/response-headers.js'; import { notAcceptableResponse, okRangeResponse } from '../utils/responses.js'; import { isObjectNode } from '../utils/walk-path.js'; import { BasePlugin } from './plugin-base.js'; /** * Handles `dag-cbor` content, including requests with Accept: `application/vnd.ipld.dag-json` and `application/json`. */ export class DagCborPlugin extends BasePlugin { id = 'dag-cbor-plugin'; codes = [ipldDagCbor.code]; canHandle({ cid, accept, pathDetails, byteRangeContext, plugins }) { this.log('checking if we can handle %c with accept %s', cid, accept); if (pathDetails == null) { return false; } if (!isObjectNode(pathDetails.terminalElement)) { return false; } if (cid.code !== ipldDagCbor.code) { return false; } if (byteRangeContext == null) { return false; } if (accept != null && accept.includes('text/html') && plugins.includes('dag-cbor-plugin-html-preview')) { // let the dag-cbor-html-preview plugin handle it return false; } return isObjectNode(pathDetails.terminalElement); } async handle(context) { const { cid, path, resource, accept, pathDetails: { terminalElement, ipfsRoots } } = context; this.log.trace('fetching %c/%s', cid, path); const block = terminalElement.node; let body; if (accept === 'application/octet-stream' || accept === 'application/vnd.ipld.dag-cbor' || accept === 'application/cbor') { // skip decoding body = block; } else if (accept === 'application/vnd.ipld.dag-json') { try { // if vnd.ipld.dag-json has been specified, convert to the format - note // that this supports more data types than regular JSON, the content-type // response header is set so the user knows to process it differently const obj = ipldDagCbor.decode(block); body = ipldDagJson.encode(obj); } catch (err) { this.log.error('could not transform %c to application/vnd.ipld.dag-json', err); return notAcceptableResponse(resource); } } else { try { body = dagCborToSafeJSON(block); } catch (err) { if (accept === 'application/json') { this.log('could not decode DAG-CBOR as JSON-safe, but the client sent "Accept: application/json"', err); return notAcceptableResponse(resource); } this.log('could not decode DAG-CBOR as JSON-safe, falling back to `application/octet-stream`', err); body = block; } } context.byteRangeContext.setBody(body); const responseContentType = accept ?? (body instanceof Uint8Array ? 'application/octet-stream' : 'application/json'); const response = okRangeResponse(resource, context.byteRangeContext.getBody(responseContentType), { byteRangeContext: context.byteRangeContext, log: this.log }); response.headers.set('content-type', context.byteRangeContext.getContentType() ?? responseContentType); this.log.trace('setting content type to "%s"', context.byteRangeContext.getContentType() ?? responseContentType); setIpfsRoots(response, ipfsRoots); return response; } } //# sourceMappingURL=plugin-handle-dag-cbor.js.map