Skip to content

Commit

Permalink
Merge pull request #13 from b6pzeusbc54tvhw5jgpyw8pwz2x6gs/12-fix-wro…
Browse files Browse the repository at this point in the history
…ng-response-when-repeated-requests-for-external-source

fix wrong response when repeated requests for external source (#12)
  • Loading branch information
ofhouse authored Mar 15, 2021
2 parents 9af519d + c3e4fdd commit 9cfae50
Show file tree
Hide file tree
Showing 9 changed files with 648 additions and 351 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ node_modules
**/.terraform/*
*.tfstate
*.tfstate.*

# IntelliJ IDEA
/.idea/
13 changes: 13 additions & 0 deletions lib/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import S3 from 'aws-sdk/clients/s3';

import { imageOptimizer, S3Config } from './image-optimizer';
import { normalizeHeaders } from './normalized-headers';
import { createDeferred } from './utils';

function generateS3Config(bucketName?: string): S3Config | undefined {
let s3: S3;
Expand Down Expand Up @@ -81,6 +82,8 @@ export async function handler(

const resBuffers: Buffer[] = [];
const resMock: any = new Writable();
const defer = createDeferred();
let didCallEnd = false;

resMock.write = (chunk: Buffer | string) => {
resBuffers.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
Expand All @@ -98,6 +101,13 @@ export async function handler(
(mockHeaders[name.toLowerCase()] = value);
resMock._implicitHeader = () => {};

resMock.originalEnd = resMock.end;
resMock.on('close', () => defer.resolve());
resMock.end = (message: any) => {
didCallEnd = true;
resMock.originalEnd(message);
};

const parsedUrl = parseUrl(reqMock.url, true);
const result = await imageOptimizer(
imageConfig,
Expand All @@ -123,6 +133,9 @@ export async function handler(
normalizedHeaders['cache-control'] = 'public, max-age=60';
}

if (didCallEnd) defer.resolve();
await defer.promise;

return {
statusCode: resMock.statusCode || 200,
body: Buffer.concat(resBuffers).toString('base64'),
Expand Down
19 changes: 19 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface Deferred<T = never> {
promise: Promise<T>;
resolve: (value?: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
}

export function createDeferred<T>() {
let r;
let j;

const promise = new Promise<T>(
(resolve: (value: any) => void, reject: (reason?: any) => void): void => {
r = resolve;
j = reject;
}
);

return ({ promise, resolve: r, reject: j } as unknown) as Deferred<T>;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"test:e2e": "jest --testTimeout=60000 e2e.*"
},
"devDependencies": {
"@dealmore/sammy": "^1.3.0",
"@dealmore/sammy": "^1.5.0",
"@types/jest": "^26.0.20",
"@types/mime": "^2.0.3",
"@types/node": "^12.0.0",
Expand Down
66 changes: 66 additions & 0 deletions test/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,71 @@ describe('[e2e]', () => {
});
});

describe('From filesystem cache for external image', () => {
let lambdaSAM: LambdaSAM;
beforeAll(async () => {
// Generate SAM for the worker lambda
lambdaSAM = await generateSAM({
lambdas: {
imageOptimizer: {
filename: 'dist.zip',
handler: 'handler.handler',
runtime: NODE_RUNTIME,
memorySize: 1024,
route,
method: 'get',
environment: {
TF_NEXTIMAGE_DOMAINS: JSON.stringify([hostIpAddress]),
},
},
},
cwd: pathToWorker,
onData: (data) => console.log(data.toString()),
onError: (data) => console.log(data.toString()),
cliOptions: { warmContainers: 'EAGER' },
});

await lambdaSAM.start();
});

afterAll(async () => {
await lambdaSAM.stop();
});
test.each([
"internet. (first call)",
"hitting filesystem cache. (2nd call)",
])("Fetch external image by %s", async () => {
const [filePath, fixtureResponse] = acceptAllFixtures.find(f => f[1].ext === 'png') || []
if (!filePath || !fixtureResponse) throw new Error('Can not found png file path')

const publicPath = `http://${s3Endpoint}/${fixtureBucketName}/${filePath}`;
const [w,q] = ['2048','75']
const optimizerParams = new URLSearchParams({ url: publicPath, w, q })
const optimizerPrefix = `external_accept_all_w-${w}_q-${q}_`;
const snapshotFileName = path.join(
__dirname,
'__snapshots__/e2e/',
`${optimizerPrefix}${filePath.replace('/', '_')}.${fixtureResponse.ext}`
);

const response = await lambdaSAM.sendApiGwRequest(
`${route}?${optimizerParams.toString()}`
);
const text = await response.text();
const body = Buffer.from(text, 'base64');

expect(response.status).toBe(200);
expect(body).toMatchFile(snapshotFileName);
expect(response.headers.get('Content-Type')).toBe(
fixtureResponse['content-type']
);
expect(response.headers.get('Cache-Control')).toBe(cacheControlHeader);

// Header settings needed for CloudFront compression
expect(response.headers.has('Content-Length')).toBeTruthy();
expect(response.headers.has('Content-Encoding')).toBeFalsy();
})
})

test.todo('Run test against domain that is not on the list');
});
2 changes: 1 addition & 1 deletion test/image-optimizer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import S3 from 'aws-sdk/clients/s3';
import * as path from 'path';

import { imageOptimizer, S3Config } from '../lib/image-optimizer';
import { createDeferred } from './utils';
import { createDeferred } from '../lib/utils';
import { s3PublicDir } from './utils/s3-public-dir';
import { acceptAllFixtures, acceptWebpFixtures } from './constants';

Expand Down
4 changes: 4 additions & 0 deletions test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ export function createDeferred<T>() {

return ({ promise, resolve: r, reject: j } as unknown) as Deferred<T>;
}

export const delay = (ms: number) => new Promise(resolve => {
setTimeout(resolve, ms)
})
Loading

0 comments on commit 9cfae50

Please sign in to comment.