Skip to content

Commit

Permalink
fix: implicit accept header can be overridden by format query
Browse files Browse the repository at this point in the history
  • Loading branch information
SgtPooki committed Mar 30, 2024
1 parent 39bb14e commit 02c3c45
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 3 deletions.
3 changes: 2 additions & 1 deletion packages/verified-fetch/src/utils/select-output-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const CID_TYPE_MAP: Record<number, string[]> = {
'application/octet-stream',
'application/vnd.ipld.raw',
'application/vnd.ipfs.ipns-record',
'application/vnd.ipld.dag-json',
'application/vnd.ipld.car',
'application/x-tar'
]
Expand Down Expand Up @@ -145,7 +146,7 @@ function parseQFactor (str?: string): number {
return factor
}

const FORMAT_TO_MIME_TYPE: Record<RequestFormatShorthand, string> = {
export const FORMAT_TO_MIME_TYPE: Record<RequestFormatShorthand, string> = {
raw: 'application/vnd.ipld.raw',
car: 'application/vnd.ipld.car',
'dag-json': 'application/vnd.ipld.dag-json',
Expand Down
13 changes: 11 additions & 2 deletions packages/verified-fetch/src/verified-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { tarStream } from './utils/get-tar-stream.js'
import { parseResource } from './utils/parse-resource.js'
import { setCacheControlHeader } from './utils/response-headers.js'
import { badRequestResponse, movedPermanentlyResponse, notAcceptableResponse, notSupportedResponse, okResponse, badRangeResponse, okRangeResponse, badGatewayResponse } from './utils/responses.js'
import { selectOutputType, queryFormatToAcceptHeader } from './utils/select-output-type.js'
import { selectOutputType, queryFormatToAcceptHeader, FORMAT_TO_MIME_TYPE } from './utils/select-output-type.js'
import { walkPath } from './utils/walk-path.js'
import type { CIDDetail, ContentTypeParser, Resource, VerifiedFetchInit as VerifiedFetchOptions } from './index.js'
import type { RequestFormatShorthand } from './types.js'
Expand Down Expand Up @@ -512,7 +512,16 @@ export class VerifiedFetch {
this.log('incoming query format "%s", mapped to %s', query.format, queryFormatMapping)
}

const acceptHeader = incomingAcceptHeader ?? queryFormatMapping
let acceptHeader: string | undefined
// if the incomingAcceptHeader is autogenerated by the requesting client (browser/curl/fetch/etc) then we may need to override it if query.format is specified
if (queryFormatMapping != null && (incomingAcceptHeader == null || !Object.values(FORMAT_TO_MIME_TYPE).includes(incomingAcceptHeader))) {
this.log('accept header not recognized, but query format provided, setting accept header to %s', queryFormatMapping)
acceptHeader = queryFormatMapping
} else {
acceptHeader = incomingAcceptHeader ?? queryFormatMapping
}
this.log('determined accept header "%s"', acceptHeader)

const accept = selectOutputType(cid, acceptHeader)
this.log('output type %s', accept)

Expand Down
58 changes: 58 additions & 0 deletions packages/verified-fetch/test/verified-fetch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,4 +710,62 @@ describe('@helia/verifed-fetch', () => {
expect(output).to.deep.equal(obj)
})
})

describe('?format', () => {
let helia: Helia
let verifiedFetch: VerifiedFetch
let contentTypeParser: Sinon.SinonStub

beforeEach(async () => {
contentTypeParser = Sinon.stub()
helia = await createHelia()
verifiedFetch = new VerifiedFetch({
helia
}, {
contentTypeParser
})
})

afterEach(async () => {
await stop(helia, verifiedFetch)
})

it('cbor?format=dag-json should be able to override curl/browser default accept header when query parameter is provided', async () => {
const obj = {
hello: 'world'
}
const c = dagCbor(helia)
const cid = await c.add(obj)

const resp = await verifiedFetch.fetch(`http://example.com/ipfs/${cid}?format=dag-json`, {
headers: {
// see https://github.com/ipfs/helia-verified-fetch/issues/35
// accept: '*/*'
}
})
expect(resp.headers.get('content-type')).to.equal('application/vnd.ipld.dag-json')
const data = ipldDagJson.decode(await resp.arrayBuffer())
expect(data).to.deep.equal(obj)
})

it('raw?format=dag-json should be able to override curl/browser default accept header when query parameter is provided', async () => {
const finalRootFileContent = uint8ArrayFromString(JSON.stringify({
hello: 'world'
}))
const cid = CID.createV1(raw.code, await sha256.digest(finalRootFileContent))
await helia.blockstore.put(cid, finalRootFileContent)

const resp = await verifiedFetch.fetch(`http://example.com/ipfs/${cid}?format=dag-json`, {
headers: {
// see https://github.com/ipfs/helia-verified-fetch/issues/35
accept: '*/*'
}
})
expect(resp).to.be.ok()
expect(resp.status).to.equal(200)
expect(resp.statusText).to.equal('OK')
const data = await resp.arrayBuffer()
expect(new Uint8Array(data)).to.equalBytes(finalRootFileContent)
})
})
})

0 comments on commit 02c3c45

Please sign in to comment.