From b0927b8192680ae63c0ef205a46c4e7d22ed4ab4 Mon Sep 17 00:00:00 2001 From: Brett Andrews Date: Mon, 25 Jun 2018 08:05:34 -0700 Subject: [PATCH 1/3] fix: apply Content-Length header when missing * Certain requests (e.g. GET and DELETE) would fail when they included a body due to missing content-length header. See #147, #106, #130 --- __tests__/unit.js | 2 ++ package.json | 2 +- src/index.js | 28 ++++++++++++++++++++-------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/__tests__/unit.js b/__tests__/unit.js index 6462d1df..55f94ade 100644 --- a/__tests__/unit.js +++ b/__tests__/unit.js @@ -72,6 +72,7 @@ test('mapApiGatewayEventToHttpRequest: with headers', () => { path: '/foo', headers: { 'x-foo': 'foo', + 'Content-Length': Buffer.byteLength('Hello serverless!'), 'x-apigateway-event': encodeURIComponent(JSON.stringify(r.eventClone)), 'x-apigateway-context': encodeURIComponent(JSON.stringify(r.context)) }, @@ -86,6 +87,7 @@ test('mapApiGatewayEventToHttpRequest: without headers', () => { method: 'GET', path: '/foo', headers: { + 'Content-Length': Buffer.byteLength('Hello serverless!'), 'x-apigateway-event': encodeURIComponent(JSON.stringify(r.eventClone)), 'x-apigateway-context': encodeURIComponent(JSON.stringify(r.context)) }, diff --git a/package.json b/package.json index 5827ea25..33a8e3e0 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ }, "scripts": { "test": "jest", - "test-watch": "jest --watch", + "test:watch": "jest --watch", "coverage": "jest --coverage", "cz": "git-cz", "release": "semantic-release", diff --git a/src/index.js b/src/index.js index 98fc2169..3db57d31 100644 --- a/src/index.js +++ b/src/index.js @@ -21,6 +21,13 @@ const isType = require('type-is') function getPathWithQueryStringParams (event) { return url.format({ pathname: event.path, query: event.queryStringParameters }) } +function getEventBody (event) { + return Buffer.from(event.body, event.isBase64Encoded ? 'base64' : 'utf8') +} + +function clone (json) { + return JSON.parse(JSON.stringify(json)) +} function getContentType (params) { // only compare mime type; ignore encoding part @@ -32,11 +39,18 @@ function isContentTypeBinaryMimeType (params) { } function mapApiGatewayEventToHttpRequest (event, context, socketPath) { - const headers = event.headers || {} // NOTE: Mutating event.headers; prefer deep clone of event.headers - const eventWithoutBody = Object.assign({}, event) - delete eventWithoutBody.body + const headers = Object.assign({}, event.headers) - headers['x-apigateway-event'] = encodeURIComponent(JSON.stringify(eventWithoutBody)) + // NOTE: API Gateway is not setting Content-Length header on requests even when they have a body + if (event.body && !headers['Content-Length']) { + const body = getEventBody(event) + headers['Content-Length'] = Buffer.byteLength(body) + } + + const clonedEventWithoutBody = clone(event) + delete clonedEventWithoutBody.body + + headers['x-apigateway-event'] = encodeURIComponent(JSON.stringify(clonedEventWithoutBody)) headers['x-apigateway-context'] = encodeURIComponent(JSON.stringify(context)) return { @@ -121,11 +135,9 @@ function forwardRequestToNodeServer (server, event, context, resolver) { const requestOptions = mapApiGatewayEventToHttpRequest(event, context, getSocketPath(server._socketPathSuffix)) const req = http.request(requestOptions, (response) => forwardResponseToApiGateway(server, response, resolver)) if (event.body) { - if (event.isBase64Encoded) { - event.body = Buffer.from(event.body, 'base64') - } + const body = getEventBody(event) - req.write(event.body) + req.write(body) } req.on('error', (error) => forwardConnectionErrorResponseToApiGateway(error, resolver)) From 790e976305fac46303f5ceaa8e0b0c5dd6bb62d7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Aug 2018 21:07:31 -0700 Subject: [PATCH 2/3] test: add test for resolutionMode with fresh server --- __tests__/integration.js | 24 +++++++++++++++++++++++- package.json | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/__tests__/integration.js b/__tests__/integration.js index 2c112ce4..1cdf5f55 100644 --- a/__tests__/integration.js +++ b/__tests__/integration.js @@ -6,7 +6,7 @@ const app = require('../examples/basic-starter/app') const server = awsServerlessExpress.createServer(app) const lambdaFunction = { - handler: (event, context, resolutionMode, callback) => awsServerlessExpress.proxy(server, event, context, resolutionMode, callback) + handler: (event, context, resolutionMode, callback, _server = server) => awsServerlessExpress.proxy(_server, event, context, resolutionMode, callback) } function clone (json) { @@ -96,6 +96,7 @@ describe('integration tests', () => { succeed }) }) + test('GET JSON collection', (done) => { const succeed = response => { delete response.headers.date @@ -199,6 +200,27 @@ describe('integration tests', () => { .promise.then(succeed) }) + test('GET JSON single (resolutionMode = PROMISE; new server)', (done) => { + const succeed = response => { + delete response.headers.date + expect(response).toEqual(makeResponse({ + 'body': '{"id":1,"name":"Joe"}', + 'headers': { + 'content-length': '21', + 'etag': 'W/"15-rRboW+j/yFKqYqV6yklp53+fANQ"' + } + })) + newServer.close() + done() + } + const newServer = awsServerlessExpress.createServer(app) + lambdaFunction.handler(makeEvent({ + path: '/users/1', + httpMethod: 'GET' + }), {}, 'PROMISE', null, newServer) + .promise.then(succeed) + }) + test('GET JSON single 404', (done) => { const succeed = response => { delete response.headers.date diff --git a/package.json b/package.json index 33a8e3e0..7acd512a 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "path": "@semantic-release/git", "assets": [ "package.json", + "package-lock.json", "CHANGELOG.md", "dist/**/*.{js|css}" ], From 6eb8ad9405a811545dffb9f2cc76d29de6b930b1 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 17 Aug 2018 11:43:03 -0700 Subject: [PATCH 3/3] test: fix test for Node.js 4 --- __tests__/integration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/integration.js b/__tests__/integration.js index 1cdf5f55..de33044d 100644 --- a/__tests__/integration.js +++ b/__tests__/integration.js @@ -6,7 +6,7 @@ const app = require('../examples/basic-starter/app') const server = awsServerlessExpress.createServer(app) const lambdaFunction = { - handler: (event, context, resolutionMode, callback, _server = server) => awsServerlessExpress.proxy(_server, event, context, resolutionMode, callback) + handler: (event, context, resolutionMode, callback, _server) => awsServerlessExpress.proxy(_server || server, event, context, resolutionMode, callback) } function clone (json) {