diff --git a/src/client/ContentClient.ts b/src/client/ContentClient.ts index 8ab0094..765c834 100644 --- a/src/client/ContentClient.ts +++ b/src/client/ContentClient.ts @@ -25,7 +25,7 @@ export type ContentClient = { fetchEntitiesByPointers(pointers: string[], options?: RequestOptions): Promise fetchEntitiesByIds(ids: string[], options?: RequestOptions): Promise fetchEntityById(id: string, options?: RequestOptions): Promise - downloadContent(contentHash: string, options?: RequestOptions): Promise + downloadContent(contentHash: string, options?: RequestOptions & { avoidChecks?: boolean }): Promise isContentAvailable(cids: string[], options?: RequestOptions): Promise @@ -39,7 +39,7 @@ export async function downloadContent( fetcher: IFetchComponent, baseUrl: string, contentHash: string, - options?: Partial + options?: Partial & { avoidChecks?: boolean } ): Promise { const { attempts = 3, retryDelay = 500 } = options ? options : {} const timeout = options?.timeout ? { timeout: options.timeout } : {} @@ -48,14 +48,16 @@ export async function downloadContent( `fetch file with hash ${contentHash} from ${baseUrl}`, async () => { const content = await (await fetcher.fetch(`${baseUrl}/${contentHash}`, timeout)).buffer() - const downloadedHash = contentHash.startsWith('Qm') ? await hashV0(content) : await hashV1(content) + if (!options?.avoidChecks) { + const downloadedHash = contentHash.startsWith('Qm') ? await hashV0(content) : await hashV1(content) - // Sometimes, the downloaded file is not complete, so the hash turns out to be different. - // So we will check the hash before considering the download successful. - if (downloadedHash === contentHash) { - return content + // Sometimes, the downloaded file is not complete, so the hash turns out to be different. + // So we will check the hash before considering the download successful. + if (downloadedHash !== contentHash) { + throw new Error(`Failed to fetch file with hash ${contentHash} from ${baseUrl}`) + } } - throw new Error(`Failed to fetch file with hash ${contentHash} from ${baseUrl}`) + return content }, attempts, retryDelay diff --git a/test/ContentClient.spec.ts b/test/ContentClient.spec.ts index 613cf1b..1ffd1d2 100644 --- a/test/ContentClient.spec.ts +++ b/test/ContentClient.spec.ts @@ -3,7 +3,6 @@ import { Entity, EntityType } from '@dcl/schemas' import { createFetchComponent } from '@well-known-components/fetch-component' import { IFetchComponent } from '@well-known-components/http-server' import { AvailableContentResult, ContentClient, createContentClient } from '../src' -import { getCurrentVersion } from '../src/client/utils/Helper' describe('ContentClient', () => { const URL = 'https://url.com' @@ -161,6 +160,23 @@ describe('ContentClient', () => { expect(fetcher.fetch).toHaveBeenCalledTimes(2) }) + it("when a file is download, then the client doesn't check if the file is correct if the avoid checks flags is set", async () => { + const failBuffer = Buffer.from('Fail') + const realBuffer = Buffer.from('Real') + + const fileHash = await hashV0(realBuffer) + + const fetcher = createFetchComponent() + fetcher.fetch = jest.fn().mockResolvedValue({ + buffer: jest.fn().mockResolvedValueOnce(failBuffer).mockResolvedValueOnce(realBuffer) + }) + + const client = buildClient(URL, fetcher) + const result = await client.downloadContent(fileHash, { retryDelay: 20, avoidChecks: true }) + expect(result).toEqual(failBuffer) + expect(fetcher.fetch).toHaveBeenCalledTimes(1) + }) + it('When a file is downloaded and all attempts failed, then an exception is thrown', async () => { const failBuffer = Buffer.from('Fail') const fileHash = 'Hash'