Skip to content

Commit

Permalink
fix: apply Content-Length header when missing
Browse files Browse the repository at this point in the history
* Certain requests (e.g. GET and DELETE) would fail when they included a body due to missing content-length header. See #147, #106, #130
  • Loading branch information
brettstack authored and semantic-release-bot committed Aug 16, 2018
1 parent bc7bdaf commit b0927b8
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 9 deletions.
2 changes: 2 additions & 0 deletions __tests__/unit.js
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
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -104,7 +104,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
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 b0927b8

Please sign in to comment.