From 30e81e05e26b5b3191c2fdfbd20e8d6423fa30f6 Mon Sep 17 00:00:00 2001 From: Alejo Thomas Ortega Date: Fri, 11 Oct 2024 21:43:02 -0300 Subject: [PATCH 1/3] fix: opt-in for calculated Content-Type --- content/src/controller/handlers/get-content-handler.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/content/src/controller/handlers/get-content-handler.ts b/content/src/controller/handlers/get-content-handler.ts index e70d2e269..e949ae2cc 100644 --- a/content/src/controller/handlers/get-content-handler.ts +++ b/content/src/controller/handlers/get-content-handler.ts @@ -4,6 +4,8 @@ import { createContentFileHeaders } from '../utils' // Method: GET or HEAD export async function getContentHandler(context: HandlerContextWithPath<'storage', '/contents/:hashId'>) { + const shouldCalculateContentType = context.request.headers.get('Accept') === 'Any' + //url.searchParams.has('calculateContentType') const hash = context.params.hashId const content: ContentItem | undefined = await context.components.storage.retrieve(hash) @@ -11,9 +13,13 @@ export async function getContentHandler(context: HandlerContextWithPath<'storage throw new NotFoundError(`No content found with hash ${hash}`) } + const calculatedHeaders = await createContentFileHeaders(content, hash) + return { status: 200, - headers: await createContentFileHeaders(content, hash), + headers: shouldCalculateContentType + ? calculatedHeaders + : { ...calculatedHeaders, 'Content-Type': 'application/json' }, body: context.request.method.toUpperCase() === 'GET' ? await content.asRawStream() : undefined } } From e5f4804b77fb9e77348ce3ba02af7f4013073c1a Mon Sep 17 00:00:00 2001 From: Alejo Thomas Ortega Date: Fri, 11 Oct 2024 21:59:55 -0300 Subject: [PATCH 2/3] fix: tests --- .../controller/entity-metadata.spec.ts | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/content/test/integration/controller/entity-metadata.spec.ts b/content/test/integration/controller/entity-metadata.spec.ts index 90cea2bd9..7c5e42098 100644 --- a/content/test/integration/controller/entity-metadata.spec.ts +++ b/content/test/integration/controller/entity-metadata.spec.ts @@ -98,7 +98,46 @@ describe('Integration - Get wearable image and thumbnail', () => { }) describe('image', () => { - it('when entity has not image, it should return 404', async () => { + it('when entity has not image, it should return 404 with Accept=Any', async () => { + const deployResult = await buildDeployData(['wearable'], { + metadata: { thumbnail: 'some-binary-file.png' }, + contentPaths: ['test/integration/resources/some-binary-file.png'] + }) + + await server.deployEntity(deployResult.deployData) + + const responses = await Promise.all([ + fetch(`${server.getUrl()}/queries/items/wearable/image`, { headers: { Accept: 'Any' } }), + fetch(`${server.getUrl()}/queries/items/wearable/image`, { method: 'HEAD', headers: { Accept: 'Any' } }) + ]) + + for (const response of responses) { + expect(response.status).toEqual(404) + } + }) + + it('when entity has image, it should return the content and set the headers with Accept=Any', async () => { + const deployResult = await buildDeployData(['wearable'], { + metadata: { image: 'some-binary-file.png' }, + contentPaths: ['test/integration/resources/some-binary-file.png'] + }) + + await server.deployEntity(deployResult.deployData) + + const responses = await Promise.all([ + fetch(`${server.getUrl()}/queries/items/wearable/image`, { headers: { Accept: 'Any' } }), + fetch(`${server.getUrl()}/queries/items/wearable/image`, { method: 'HEAD', headers: { Accept: 'Any' } }) + ]) + + for (const response of responses) { + expect(response.status).toEqual(200) + expect(response.headers.get('content-type')).toEqual('image/png') + expect(response.headers.get('ETag')).toBeTruthy() + expect(response.headers.get('Cache-Control')).toBeTruthy() + } + }) + + it('when entity has not image, it should return 404 without Accept=Any', async () => { const deployResult = await buildDeployData(['wearable'], { metadata: { thumbnail: 'some-binary-file.png' }, contentPaths: ['test/integration/resources/some-binary-file.png'] @@ -116,7 +155,7 @@ describe('Integration - Get wearable image and thumbnail', () => { } }) - it('when entity has image, it should return the content and set the headers', async () => { + it('when entity has image, it should return the content and set the headers without Accept=Any', async () => { const deployResult = await buildDeployData(['wearable'], { metadata: { image: 'some-binary-file.png' }, contentPaths: ['test/integration/resources/some-binary-file.png'] From 8cefd873f956886ee63dc2ed07d4705eeaae26f2 Mon Sep 17 00:00:00 2001 From: Alejo Thomas Ortega Date: Fri, 11 Oct 2024 22:00:41 -0300 Subject: [PATCH 3/3] complete --- .../handlers/get-content-handler.ts | 3 +- .../controller/entity-metadata.spec.ts | 43 +------------------ 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/content/src/controller/handlers/get-content-handler.ts b/content/src/controller/handlers/get-content-handler.ts index e949ae2cc..5504b0cbb 100644 --- a/content/src/controller/handlers/get-content-handler.ts +++ b/content/src/controller/handlers/get-content-handler.ts @@ -5,7 +5,6 @@ import { createContentFileHeaders } from '../utils' // Method: GET or HEAD export async function getContentHandler(context: HandlerContextWithPath<'storage', '/contents/:hashId'>) { const shouldCalculateContentType = context.request.headers.get('Accept') === 'Any' - //url.searchParams.has('calculateContentType') const hash = context.params.hashId const content: ContentItem | undefined = await context.components.storage.retrieve(hash) @@ -19,7 +18,7 @@ export async function getContentHandler(context: HandlerContextWithPath<'storage status: 200, headers: shouldCalculateContentType ? calculatedHeaders - : { ...calculatedHeaders, 'Content-Type': 'application/json' }, + : { ...calculatedHeaders, 'Content-Type': 'application/octet-stream' }, body: context.request.method.toUpperCase() === 'GET' ? await content.asRawStream() : undefined } } diff --git a/content/test/integration/controller/entity-metadata.spec.ts b/content/test/integration/controller/entity-metadata.spec.ts index 7c5e42098..7f8b5e64d 100644 --- a/content/test/integration/controller/entity-metadata.spec.ts +++ b/content/test/integration/controller/entity-metadata.spec.ts @@ -98,7 +98,7 @@ describe('Integration - Get wearable image and thumbnail', () => { }) describe('image', () => { - it('when entity has not image, it should return 404 with Accept=Any', async () => { + it('when entity has not image, it should return 404 with', async () => { const deployResult = await buildDeployData(['wearable'], { metadata: { thumbnail: 'some-binary-file.png' }, contentPaths: ['test/integration/resources/some-binary-file.png'] @@ -116,7 +116,7 @@ describe('Integration - Get wearable image and thumbnail', () => { } }) - it('when entity has image, it should return the content and set the headers with Accept=Any', async () => { + it('when entity has image, it should return the content and set the headers', async () => { const deployResult = await buildDeployData(['wearable'], { metadata: { image: 'some-binary-file.png' }, contentPaths: ['test/integration/resources/some-binary-file.png'] @@ -136,44 +136,5 @@ describe('Integration - Get wearable image and thumbnail', () => { expect(response.headers.get('Cache-Control')).toBeTruthy() } }) - - it('when entity has not image, it should return 404 without Accept=Any', async () => { - const deployResult = await buildDeployData(['wearable'], { - metadata: { thumbnail: 'some-binary-file.png' }, - contentPaths: ['test/integration/resources/some-binary-file.png'] - }) - - await server.deployEntity(deployResult.deployData) - - const responses = await Promise.all([ - fetch(`${server.getUrl()}/queries/items/wearable/image`), - fetch(`${server.getUrl()}/queries/items/wearable/image`, { method: 'HEAD' }) - ]) - - for (const response of responses) { - expect(response.status).toEqual(404) - } - }) - - it('when entity has image, it should return the content and set the headers without Accept=Any', async () => { - const deployResult = await buildDeployData(['wearable'], { - metadata: { image: 'some-binary-file.png' }, - contentPaths: ['test/integration/resources/some-binary-file.png'] - }) - - await server.deployEntity(deployResult.deployData) - - const responses = await Promise.all([ - fetch(`${server.getUrl()}/queries/items/wearable/image`), - fetch(`${server.getUrl()}/queries/items/wearable/image`, { method: 'HEAD' }) - ]) - - for (const response of responses) { - expect(response.status).toEqual(200) - expect(response.headers.get('content-type')).toEqual('image/png') - expect(response.headers.get('ETag')).toBeTruthy() - expect(response.headers.get('Cache-Control')).toBeTruthy() - } - }) }) })