From 8f0162da4ed2a9bcf22a0a3c2612988316d9cdfc Mon Sep 17 00:00:00 2001 From: Dominic Garms Date: Mon, 5 Mar 2018 14:21:48 +0800 Subject: [PATCH 1/5] add ETag to header output --- src/handler.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/handler.ts b/src/handler.ts index 02d7a65..0dea221 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -58,6 +58,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { ContentLength, ContentType, ContentDisposition, + ETag } = await s3.headObject(options).promise() if (ContentLength! > 25 * 1024 * 1024) { @@ -82,7 +83,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { ) { const obj = await s3.getObject(options).promise() const body = (obj.Body as Buffer).toString('base64') - return base64Response(body, ContentType!, ContentDisposition!) + return base64Response(body, ContentType!, ContentDisposition!, ETag!) } const s3Resp = await s3.getObject(options).promise() @@ -125,6 +126,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { buf.toString('base64'), ContentType!, ContentDisposition!, + ETag! ) }) @@ -132,6 +134,7 @@ function base64Response( body: string, ContentType: string, ContentDisposition: string, + ETag: string ) { return { statusCode: 200, @@ -139,6 +142,7 @@ function base64Response( 'Content-Type': ContentType, 'Content-Disposition': ContentDisposition, 'Cache-Control': 'max-age=31536000', + 'E-Tag': ETag }, body, isBase64Encoded: true, From 9e3ce7a1e8e4b971df724eb714d5c01937ddc090 Mon Sep 17 00:00:00 2001 From: Dominic Garms Date: Mon, 5 Mar 2018 15:04:45 +0800 Subject: [PATCH 2/5] add last modified header --- src/handler.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index 0dea221..091a4fd 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -58,7 +58,8 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { ContentLength, ContentType, ContentDisposition, - ETag + ETag, + LastModified } = await s3.headObject(options).promise() if (ContentLength! > 25 * 1024 * 1024) { @@ -83,7 +84,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { ) { const obj = await s3.getObject(options).promise() const body = (obj.Body as Buffer).toString('base64') - return base64Response(body, ContentType!, ContentDisposition!, ETag!) + return base64Response(body, ContentType!, ContentDisposition!, ETag!, LastModified!) } const s3Resp = await s3.getObject(options).promise() @@ -126,7 +127,8 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { buf.toString('base64'), ContentType!, ContentDisposition!, - ETag! + ETag!, + LastModified! ) }) @@ -134,7 +136,8 @@ function base64Response( body: string, ContentType: string, ContentDisposition: string, - ETag: string + ETag: string, + LastModified: any ) { return { statusCode: 200, @@ -142,7 +145,8 @@ function base64Response( 'Content-Type': ContentType, 'Content-Disposition': ContentDisposition, 'Cache-Control': 'max-age=31536000', - 'E-Tag': ETag + 'ETag': ETag, + 'Last-Modified': LastModified }, body, isBase64Encoded: true, From 8155c17adfcd7ff074afe888a7792b49333a47a6 Mon Sep 17 00:00:00 2001 From: Dominic Garms Date: Thu, 8 Mar 2018 07:33:37 +0800 Subject: [PATCH 3/5] add npm etag to generate accurate ETag --- package.json | 8 +++++--- src/handler.ts | 18 ++++++------------ 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index cfa5fc2..555334a 100644 --- a/package.json +++ b/package.json @@ -12,19 +12,21 @@ }, "devDependencies": { "@types/aws-lambda": "0.0.23", + "@types/etag": "1.8.0", "@types/node": "8.5.2", "ava": "0.23.0", "husky": "0.14.3", "lint-staged": "6.0.0", "prettier": "1.9.2", - "serverless-plugin-typescript": "1.1.5", - "serverless-apigwy-binary": "0.1.0" + "serverless-apigwy-binary": "0.1.0", + "serverless-plugin-typescript": "1.1.5" }, "dependencies": { "aws-sdk": "2.176.0", "graphql-request": "1.4.1", "lambda-helpers": "0.2.2", "sharp": "0.18.4", - "source-map-support": "0.5.0" + "source-map-support": "0.5.0", + "etag": "1.8.1" } } diff --git a/src/handler.ts b/src/handler.ts index 091a4fd..1aa71f6 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -3,6 +3,7 @@ import { getConfig, parseParams, Params } from './parser' import { callbackRuntime } from 'lambda-helpers' import { APIGatewayEvent, ProxyResult } from 'aws-lambda' import { GraphQLClient } from 'graphql-request' +const etag = require('etag') const sharp = require('sharp') import 'source-map-support/register' @@ -57,9 +58,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { const { ContentLength, ContentType, - ContentDisposition, - ETag, - LastModified + ContentDisposition } = await s3.headObject(options).promise() if (ContentLength! > 25 * 1024 * 1024) { @@ -84,7 +83,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { ) { const obj = await s3.getObject(options).promise() const body = (obj.Body as Buffer).toString('base64') - return base64Response(body, ContentType!, ContentDisposition!, ETag!, LastModified!) + return base64Response(body, ContentType!, ContentDisposition!) } const s3Resp = await s3.getObject(options).promise() @@ -126,18 +125,14 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { return base64Response( buf.toString('base64'), ContentType!, - ContentDisposition!, - ETag!, - LastModified! + ContentDisposition! ) }) function base64Response( body: string, ContentType: string, - ContentDisposition: string, - ETag: string, - LastModified: any + ContentDisposition: string ) { return { statusCode: 200, @@ -145,8 +140,7 @@ function base64Response( 'Content-Type': ContentType, 'Content-Disposition': ContentDisposition, 'Cache-Control': 'max-age=31536000', - 'ETag': ETag, - 'Last-Modified': LastModified + 'ETag': etag(body) }, body, isBase64Encoded: true, From 42ddb4998f58c80543eb59882a62ebf8b312047c Mon Sep 17 00:00:00 2001 From: Dominic Garms Date: Thu, 8 Mar 2018 08:21:33 +0800 Subject: [PATCH 4/5] read If-None-Match header and compare etag to return status 304 in case not modified --- src/handler.ts | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index 1aa71f6..6d78320 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -39,6 +39,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { } } + const headerETag = event.headers['If-None-Match'] const [paramsErr, params] = parseParams(event.path) if (paramsErr) { @@ -83,7 +84,7 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { ) { const obj = await s3.getObject(options).promise() const body = (obj.Body as Buffer).toString('base64') - return base64Response(body, ContentType!, ContentDisposition!) + return base64Response(body, ContentType!, ContentDisposition!, headerETag!) } const s3Resp = await s3.getObject(options).promise() @@ -125,23 +126,35 @@ export default callbackRuntime(async (event: APIGatewayEvent) => { return base64Response( buf.toString('base64'), ContentType!, - ContentDisposition! + ContentDisposition!, + headerETag! ) }) function base64Response( body: string, ContentType: string, - ContentDisposition: string + ContentDisposition: string, + headerETag: string ) { + const bodyETag = etag(body); + const headers = { + 'Content-Type': ContentType, + 'Content-Disposition': ContentDisposition, + 'Cache-Control': 'max-age=31536000', + 'ETag': bodyETag + }; + + if(headerETag && bodyETag){ + return { + statusCode: 304, + headers: headers + } + } + return { statusCode: 200, - headers: { - 'Content-Type': ContentType, - 'Content-Disposition': ContentDisposition, - 'Cache-Control': 'max-age=31536000', - 'ETag': etag(body) - }, + headers: headers, body, isBase64Encoded: true, } From c932951deaff13915b8934f5005c2ec99c9d7a19 Mon Sep 17 00:00:00 2001 From: Dominic Garms Date: Thu, 8 Mar 2018 09:35:46 +0800 Subject: [PATCH 5/5] add missing comparison etag --- src/handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handler.ts b/src/handler.ts index 6d78320..c8af038 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -145,7 +145,7 @@ function base64Response( 'ETag': bodyETag }; - if(headerETag && bodyETag){ + if(headerETag && headerETag === bodyETag){ return { statusCode: 304, headers: headers