diff --git a/src/json-pipe.js b/src/json-pipe.js index 237997cd..995d221a 100644 --- a/src/json-pipe.js +++ b/src/json-pipe.js @@ -13,7 +13,7 @@ import fetchMetadata from './steps/fetch-metadata.js'; import setCustomResponseHeaders from './steps/set-custom-response-headers.js'; import { PipelineResponse } from './PipelineResponse.js'; import jsonFilter from './utils/json-filter.js'; -import { updateLastModified } from './utils/last-modified.js'; +import { extractLastModified, updateLastModified } from './utils/last-modified.js'; /** * Runs the default pipeline and returns the response. @@ -73,7 +73,7 @@ export async function jsonPipe(state, req) { }); // set last-modified - updateLastModified(state, response, dataResponse.headers.get('last-modified')); + updateLastModified(state, response, extractLastModified(dataResponse.headers)); // set surrogate key response.headers.set('x-surrogate-key', `${contentBusId}${path}`.replace(/\//g, '_')); diff --git a/src/steps/fetch-metadata.js b/src/steps/fetch-metadata.js index 726d5cd0..75aa3bcf 100644 --- a/src/steps/fetch-metadata.js +++ b/src/steps/fetch-metadata.js @@ -39,8 +39,8 @@ export default async function fetchMetadata(state, req, res) { } state.metadata = data; - if (state.type === 'html') { - // also update last-modified (only for html pipeline) + if (state.type === 'html' && state.info.selector !== 'plain') { + // also update last-modified (only for extensionless html pipeline) updateLastModified(state, res, extractLastModified(ret.headers)); } return; diff --git a/src/utils/last-modified.js b/src/utils/last-modified.js index e97ed4d1..eea156a8 100644 --- a/src/utils/last-modified.js +++ b/src/utils/last-modified.js @@ -41,7 +41,8 @@ export function updateLastModified(state, res, httpDate) { /** * Returns the last modified date from response headers, giving 'x-amz-meta-x-source-last-modified' * preference. - * @param {object} headers + * @param {Map} headers + * @return {string} the last modified date */ export function extractLastModified(headers) { return headers.get('x-amz-meta-x-source-last-modified') ?? headers.get('last-modified'); diff --git a/test/json-pipe.test.js b/test/json-pipe.test.js index 0843e238..99365e33 100644 --- a/test/json-pipe.test.js +++ b/test/json-pipe.test.js @@ -162,6 +162,38 @@ describe('JSON Pipe Test', () => { }); }); + it('prefers x-source-last-modified', async () => { + const state = createDefaultState(); + state.s3Loader.reply( + 'helix-content-bus', + 'foobar/preview/en/index.json', + new PipelineResponse(TEST_SINGLE_SHEET, { + headers: { + 'content-type': 'application/json', + 'x-amz-meta-x-source-location': 'foo-bar', + 'last-modified': 'Wed, 12 Oct 2009 17:50:00 GMT', + 'x-amz-meta-x-source-last-modified': 'Wed, 12 Oct 2009 15:50:00 GMT', + }, + }), + ); + + const resp = await jsonPipe(state, new PipelineRequest('https://json-filter.com/?limit=10&offset=5')); + assert.strictEqual(resp.status, 200); + assert.deepStrictEqual(await resp.json(), { + ':type': 'sheet', + offset: 5, + limit: 10, + total: TEST_DATA.length, + data: TEST_DATA.slice(5, 15), + }); + const headers = Object.fromEntries(resp.headers.entries()); + assert.deepStrictEqual(headers, { + 'last-modified': 'Wed, 12 Oct 2009 15:50:00 GMT', + 'x-surrogate-key': 'foobar_en_index.json', + 'content-type': 'application/json', + }); + }); + it('falls back to code bus if content is not found', async () => { const state = new PipelineState({ path: '/en/index.json', diff --git a/test/rendering.test.js b/test/rendering.test.js index 708f5c15..ba3be16e 100644 --- a/test/rendering.test.js +++ b/test/rendering.test.js @@ -395,6 +395,21 @@ describe('Rendering', () => { }); }); + it('ignores last modified from metadata.json for plain', async () => { + loader + .headers('helix-config.json', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2009 11:50:00 GMT') + .headers('one-section.md', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2022 12:50:00 GMT') + .headers('metadata.json', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2022 15:33:01 GMT'); + const { status, body, headers } = await render(new URL('https://helix-pipeline.com/blog/one-section'), '.plain'); + assert.strictEqual(status, 200); + assert.match(body, /

Hello<\/h1>

This is the first section.<\/p><\/div>/); + assert.deepStrictEqual(Object.fromEntries(headers.entries()), { + 'content-type': 'text/html; charset=utf-8', + 'x-surrogate-key': '0j8f6rmY3lU5kgOE', + 'last-modified': 'Wed, 12 Oct 2022 12:50:00 GMT', + }); + }); + it('uses response headers from metadata.json', async () => { loader.rewrite('metadata.json', 'metadata-headers.json'); const { headers } = await testRender('meta-response-headers', 'head');