diff --git a/packages/verified-fetch/src/utils/parse-url-string.ts b/packages/verified-fetch/src/utils/parse-url-string.ts index 4acd2255..63959365 100644 --- a/packages/verified-fetch/src/utils/parse-url-string.ts +++ b/packages/verified-fetch/src/utils/parse-url-string.ts @@ -276,5 +276,5 @@ function joinPaths (resolvedPath: string | undefined, urlPath: string): string { path = path.substring(1) } - return path + return path.split('/').map(decodeURIComponent).join('/') } diff --git a/packages/verified-fetch/test/utils/parse-url-string.spec.ts b/packages/verified-fetch/test/utils/parse-url-string.spec.ts index c09ff839..c5418622 100644 --- a/packages/verified-fetch/test/utils/parse-url-string.spec.ts +++ b/packages/verified-fetch/test/utils/parse-url-string.spec.ts @@ -339,6 +339,20 @@ describe('parseUrlString', () => { } ) }) + + // tests for https://github.com/ipfs-shipyard/service-worker-gateway/issues/83 issue + it('can parse an IPFS path with encodedURIComponents', async () => { + const rawPathLabel = "Plan_d'exécution_du_second_étage_de_l'hôtel_de_Brionne_(dessin)_De_Cotte_2503c_–_Gallica_2011_(adjusted).jpg.webp" + await assertMatchUrl( + `/ipfs/QmQJ8fxavY54CUsxMSx9aE9Rdcmvhx8awJK2jzJp4iAqCr/I/${encodeURIComponent(rawPathLabel)}`, { + protocol: 'ipfs', + cid: 'QmQJ8fxavY54CUsxMSx9aE9Rdcmvhx8awJK2jzJp4iAqCr', + // path with decoded component + path: `I/${rawPathLabel}`, + query: {} + } + ) + }) }) describe('http://example.com/ipfs/ URLs', () => { diff --git a/packages/verified-fetch/test/verified-fetch.spec.ts b/packages/verified-fetch/test/verified-fetch.spec.ts index 64cbc84e..8975ec9f 100644 --- a/packages/verified-fetch/test/verified-fetch.spec.ts +++ b/packages/verified-fetch/test/verified-fetch.spec.ts @@ -710,4 +710,42 @@ describe('@helia/verifed-fetch', () => { expect(output).to.deep.equal(obj) }) }) + + describe('encoded URI paths', () => { + let verifiedFetch: VerifiedFetch + + beforeEach(async () => { + verifiedFetch = new VerifiedFetch({ + helia + }) + }) + + afterEach(async () => { + await verifiedFetch.stop() + }) + + // tests for https://github.com/ipfs-shipyard/service-worker-gateway/issues/83 issue + it('should decode encoded URI paths', async () => { + const finalRootFileContent = new Uint8Array([0x01, 0x02, 0x03]) + + const fs = unixfs(helia) + const res = await last(fs.addAll([{ + path: "Plan_d'exécution_du_second_étage_de_l'hôtel_de_Brionne_(dessin)_De_Cotte_2503c_–_Gallica_2011_(adjusted).jpg.webp", + content: finalRootFileContent + }], { + wrapWithDirectory: true + })) + + if (res == null) { + throw new Error('Import failed') + } + const { cid } = res + const resp = await verifiedFetch.fetch(`ipfs://${cid}/${encodeURIComponent("Plan_d'exécution_du_second_étage_de_l'hôtel_de_Brionne_(dessin)_De_Cotte_2503c_–_Gallica_2011_(adjusted).jpg.webp")}`) + 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) + }) + }) })