diff --git a/package.json b/package.json index bd83760..611086c 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,8 @@ "libp2p": "^1.3.1", "multiformats": "^13.1.0", "pino-pretty": "^11.0.0", - "private-ip": "^3.0.2" + "private-ip": "^3.0.2", + "race-signal": "^1.0.2" }, "devDependencies": { "@playwright/test": "^1.43.0", diff --git a/src/helia-http-gateway.ts b/src/helia-http-gateway.ts index 4fd70e7..ad0b982 100644 --- a/src/helia-http-gateway.ts +++ b/src/helia-http-gateway.ts @@ -1,9 +1,11 @@ +import { raceSignal } from 'race-signal' import { USE_SUBDOMAINS } from './constants.js' import { dnsLinkLabelEncoder, isInlinedDnsLink } from './dns-link-labels.js' import { getFullUrlFromFastifyRequest, getRequestAwareSignal } from './helia-server.js' import { getIpnsAddressDetails } from './ipns-address-utils.js' import type { VerifiedFetch } from '@helia/verified-fetch' import type { ComponentLogger } from '@libp2p/interface' +import type { AbortOptions } from '@multiformats/multiaddr' import type { FastifyReply, FastifyRequest, RouteOptions } from 'fastify' import type { Helia } from 'helia' @@ -91,10 +93,12 @@ export function httpGateway (opts: HeliaHTTPGatewayOptions): RouteOptions[] { // internally, otherwise let the client making the request do it const resp = await opts.fetch(url, { signal, redirect: USE_SUBDOMAINS ? 'manual' : 'follow' }) - await convertVerifiedFetchResponseToFastifyReply(url, resp, reply) + await convertVerifiedFetchResponseToFastifyReply(url, resp, reply, { + signal + }) } - async function convertVerifiedFetchResponseToFastifyReply (url: string, verifiedFetchResponse: Response, reply: FastifyReply): Promise { + async function convertVerifiedFetchResponseToFastifyReply (url: string, verifiedFetchResponse: Response, reply: FastifyReply, options: AbortOptions): Promise { if (!verifiedFetchResponse.ok) { log('verified-fetch response for %s not ok: ', url, verifiedFetchResponse.status) await reply.code(verifiedFetchResponse.status).send(verifiedFetchResponse.statusText) @@ -123,14 +127,15 @@ export function httpGateway (opts: HeliaHTTPGatewayOptions): RouteOptions[] { try { let done = false while (!done) { - const { done: _done, value } = await reader.read() + const { done: _done, value } = await raceSignal(reader.read(), options.signal) if (value != null) { reply.raw.write(Buffer.from(value)) } done = _done } } catch (err) { - log.error('error reading response:', err) + log.error('error reading response for %s', url, err) + await reader.cancel(err) } finally { log.error('reading response for %s ended', url) reply.raw.end()