Skip to content

Commit

Permalink
feat: provide default content-type-parser (#193)
Browse files Browse the repository at this point in the history
* chore: in progress

* fix: accept header tests pass

* chore: log message grammar

* fix: tests passing

* chore: resolve dep-check error

* chore: remove newly unnecessary test
  • Loading branch information
SgtPooki authored Mar 10, 2025
1 parent 3df98fc commit 945dd01
Show file tree
Hide file tree
Showing 8 changed files with 18 additions and 19 deletions.
1 change: 0 additions & 1 deletion packages/gateway-conformance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
"@libp2p/logger": "^5.1.4",
"@libp2p/peer-id": "^5.0.8",
"@multiformats/dns": "^1.0.6",
"@sgtpooki/file-type": "^1.0.1",
"aegir": "^45.0.1",
"blockstore-core": "^5.0.2",
"datastore-core": "^10.0.2",
Expand Down
2 changes: 0 additions & 2 deletions packages/gateway-conformance/src/fixtures/basic-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { logger } from '@libp2p/logger'
import { dns } from '@multiformats/dns'
import { MemoryBlockstore } from 'blockstore-core'
import { Agent, setGlobalDispatcher } from 'undici'
import { contentTypeParser } from './content-type-parser.js'
import { createVerifiedFetch } from './create-verified-fetch.js'
import { getLocalDnsResolver } from './get-local-dns-resolver.js'
import { convertFetchHeadersToNodeJsHeaders, convertNodeJsHeadersToFetchHeaders } from './header-utils.js'
Expand Down Expand Up @@ -201,7 +200,6 @@ export async function startVerifiedFetchGateway ({ kuboGateway, serverPort, IPFS
const helia = await createHelia({ gateways: [kuboGateway], dnsResolvers: [localDnsResolver], blockstore, datastore })

const verifiedFetch = await createVerifiedFetch(helia, {
contentTypeParser,
plugins: [dirIndexHtmlPluginFactory]
})

Expand Down
2 changes: 1 addition & 1 deletion packages/verified-fetch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
"@libp2p/webrtc": "^5.1.0",
"@libp2p/websockets": "^9.1.5",
"@multiformats/dns": "^1.0.6",
"@sgtpooki/file-type": "^1.0.1",
"cborg": "^4.2.8",
"hashlru": "^2.3.0",
"helia": "^5.2.1",
Expand All @@ -188,7 +189,6 @@
"@helia/json": "^4.0.2",
"@ipld/car": "^5.4.0",
"@libp2p/crypto": "^5.0.11",
"@sgtpooki/file-type": "^1.0.1",
"@types/sinon": "^17.0.3",
"aegir": "^45.0.9",
"blockstore-core": "^5.0.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/verified-fetch/src/plugins/plugin-handle-raw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class RawPlugin extends BasePlugin {
context.query.filename = context.query.filename ?? `${cid.toString()}.bin`
log.trace('Set content disposition...')
} else {
log.trace('Did NOT setting content disposition...')
log.trace('Did NOT set content disposition...')
}

if (path !== '' && cid.code === rawCode) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { logger } from '@libp2p/logger'
import { fileTypeFromBuffer } from '@sgtpooki/file-type'

const log = logger('content-type-parser')
const log = logger('helia:verified-fetch:content-type-parser')

// default from verified-fetch is application/octect-stream, which forces a download. This is not what we want for MANY file types.
const defaultMimeType = 'text/html; charset=utf-8'
export const defaultMimeType = 'application/octet-stream'
function checkForSvg (bytes: Uint8Array): boolean {
log('checking for svg')
return /^(<\?xml[^>]+>)?[^<^\w]+<svg/ig.test(new TextDecoder().decode(bytes.slice(0, 64)))
Expand Down
5 changes: 5 additions & 0 deletions packages/verified-fetch/src/utils/set-content-type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type Logger } from '@libp2p/interface'
import { type ContentTypeParser } from '../types.js'
import { defaultMimeType } from './content-type-parser.js'
import { isPromise } from './type-guards.js'

export interface SetContentTypeOptions {
Expand Down Expand Up @@ -34,6 +35,10 @@ export async function setContentType ({ bytes, path, response, contentTypeParser
log.error('error parsing content type', err)
}
}
if (contentType === defaultMimeType) {
// if the content type is the default in our content-type-parser, instead, set it to the default content type provided to this function.
contentType = defaultContentType
}
log.trace('setting content type to "%s"', contentType ?? defaultContentType)
response.headers.set('content-type', contentType ?? defaultContentType)
}
3 changes: 2 additions & 1 deletion packages/verified-fetch/src/verified-fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IpnsRecordPlugin } from './plugins/plugin-handle-ipns-record.js'
import { JsonPlugin } from './plugins/plugin-handle-json.js'
import { RawPlugin } from './plugins/plugin-handle-raw.js'
import { TarPlugin } from './plugins/plugin-handle-tar.js'
import { contentTypeParser } from './utils/content-type-parser.js'
import { getContentDispositionFilename } from './utils/get-content-disposition-filename.js'
import { getETag } from './utils/get-e-tag.js'
import { getResolvedAcceptHeader } from './utils/get-resolved-accept-header.js'
Expand Down Expand Up @@ -79,7 +80,7 @@ export class VerifiedFetch {
this.helia = helia
this.log = helia.logger.forComponent('helia:verified-fetch')
this.ipns = ipns ?? heliaIpns(helia)
this.contentTypeParser = init?.contentTypeParser
this.contentTypeParser = init?.contentTypeParser ?? contentTypeParser
this.blockstoreSessions = new LRUCache({
max: init?.sessionCacheSize ?? SESSION_CACHE_MAX_SIZE,
ttl: init?.sessionTTLms ?? SESSION_CACHE_TTL_MS,
Expand Down
17 changes: 7 additions & 10 deletions packages/verified-fetch/test/content-type-parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,22 @@ describe('content-type-parser', () => {
await stop(verifiedFetch)
})

it('is used when passed to createVerifiedFetch', async () => {
const contentTypeParser = Sinon.stub().resolves('text/plain')
it('can be overriden by passing a custom contentTypeParser', async () => {
let called = false
const contentTypeParser = Sinon.stub().callsFake(() => {
called = true
return 'text/plain'
})
const fetch = await createVerifiedFetch(helia, {
contentTypeParser
})
expect(fetch).to.be.ok()
const resp = await fetch(cid)
expect(resp.headers.get('content-type')).to.equal('text/plain')
expect(called).to.equal(true)
await fetch.stop()
})

it('sets default content type if contentTypeParser is not passed', async () => {
verifiedFetch = new VerifiedFetch({
helia
})
const resp = await verifiedFetch.fetch(cid)
expect(resp.headers.get('content-type')).to.equal('application/octet-stream')
})

it('sets default content type if contentTypeParser returns undefined', async () => {
verifiedFetch = new VerifiedFetch({
helia
Expand Down

0 comments on commit 945dd01

Please sign in to comment.