Skip to content

Commit

Permalink
fix: apply Content-Length header when missing (CodeGenieApp#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
brettstack authored Aug 17, 2018
2 parents bc7bdaf + 6eb8ad9 commit c2f416b
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 10 deletions.
24 changes: 23 additions & 1 deletion __tests__/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => awsServerlessExpress.proxy(_server || server, event, context, resolutionMode, callback)
}

function clone (json) {
Expand Down Expand Up @@ -96,6 +96,7 @@ describe('integration tests', () => {
succeed
})
})

test('GET JSON collection', (done) => {
const succeed = response => {
delete response.headers.date
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions __tests__/unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))
},
Expand All @@ -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))
},
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"path": "@semantic-release/git",
"assets": [
"package.json",
"package-lock.json",
"CHANGELOG.md",
"dist/**/*.{js|css}"
],
Expand Down Expand Up @@ -104,7 +105,7 @@
},
"scripts": {
"test": "jest",
"test-watch": "jest --watch",
"test:watch": "jest --watch",
"coverage": "jest --coverage",
"cz": "git-cz",
"release": "semantic-release",
Expand Down
28 changes: 20 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit c2f416b

Please sign in to comment.