Skip to content

Commit 8c7060d

Browse files
authored
Merge pull request #41 from panva/master
support multiple headers with the same name
2 parents 09c8f8a + 7a69e03 commit 8c7060d

4 files changed

Lines changed: 55 additions & 24 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,4 @@ app.use(awsServerlessExpressMiddleware.eventContext())
8080
- May be more expensive for high-traffic apps
8181
- Cannot use native libraries (aka [Addons](https://nodejs.org/api/addons.html)) unless you package your app on an EC2 machine running Amazon Linux
8282
- Stateless only
83-
- Multiple headers with same name not currently supported
8483
- API Gateway has a timeout of 30 seconds, and Lambda has a maximum execution time of 5 minutes.

__tests__/index.js

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -84,34 +84,55 @@ test('getSocketPath', () => {
8484
expect(socketPath).toEqual('/tmp/server0.sock')
8585
})
8686

87-
describe('forwardResponseToApiGateway: content-type encoding', () => {
88-
const PassThrough = require('stream').PassThrough
89-
90-
class MockResponse extends PassThrough {
91-
constructor(statusCode, headers, body) {
92-
super()
93-
this.statusCode = statusCode
94-
this.headers = headers || {}
95-
this.write(body)
96-
this.end()
97-
}
87+
const PassThrough = require('stream').PassThrough
88+
89+
class MockResponse extends PassThrough {
90+
constructor(statusCode, headers, body) {
91+
super()
92+
this.statusCode = statusCode
93+
this.headers = headers || {}
94+
this.write(body)
95+
this.end()
9896
}
97+
}
9998

100-
class MockServer {
101-
constructor(binaryTypes) {
102-
this._binaryTypes = binaryTypes || []
103-
}
99+
class MockServer {
100+
constructor(binaryTypes) {
101+
this._binaryTypes = binaryTypes || []
104102
}
103+
}
105104

106-
class MockContext {
107-
constructor(resolve) {
108-
this.resolve = resolve
109-
}
110-
succeed(successResponse) {
111-
this.resolve(successResponse)
112-
}
105+
class MockContext {
106+
constructor(resolve) {
107+
this.resolve = resolve
108+
}
109+
succeed(successResponse) {
110+
this.resolve(successResponse)
113111
}
112+
}
114113

114+
describe('forwardResponseToApiGateway: header handling', () => {
115+
test('multiple headers with the same name get transformed', () => {
116+
const server = new MockServer()
117+
const headers = {'foo': ['bar', 'baz']}
118+
const body = 'hello world'
119+
const response = new MockResponse(200, headers, body)
120+
return new Promise(
121+
(resolve, reject) => {
122+
const context = new MockContext(resolve)
123+
awsServerlessExpress.forwardResponseToApiGateway(
124+
server, response, context)
125+
}
126+
).then(successResponse => expect(successResponse).toEqual({
127+
statusCode: 200,
128+
body: body,
129+
headers: { Foo: 'bar', fOo: 'baz' },
130+
isBase64Encoded: false
131+
}))
132+
})
133+
})
134+
135+
describe('forwardResponseToApiGateway: content-type encoding', () => {
115136
test('content-type header missing', () => {
116137
const server = new MockServer()
117138
const headers = {'foo': 'bar'}

index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
'use strict'
1616
const http = require('http')
17+
const binarycase = require('binary-case')
1718

1819
function getPathWithQueryStringParams(event) {
1920
const queryStringKeys = Object.keys(event.queryStringParameters || {})
@@ -55,9 +56,16 @@ function forwardResponseToApiGateway(server, response, context) {
5556
const statusCode = response.statusCode
5657
const headers = response.headers
5758

59+
// HACK: modifies header casing to get around API Gateway's limitation of not allowing multiple
60+
// headers with the same name, as discussed on the AWS Forum https://forums.aws.amazon.com/message.jspa?messageID=725953#725953
5861
Object.keys(headers)
5962
.forEach(h => {
60-
if(Array.isArray(headers[h])) headers[h] = headers[h].join(',')
63+
if(Array.isArray(headers[h])) {
64+
headers[h].forEach((value, i) => {
65+
headers[binarycase(h, i + 1)] = value
66+
})
67+
delete headers[h]
68+
}
6169
})
6270

6371
const contentType = headers['content-type']

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,8 @@
3232
},
3333
"scripts": {
3434
"test": "jest"
35+
},
36+
"dependencies": {
37+
"binary-case": "^1.0.0"
3538
}
3639
}

0 commit comments

Comments
 (0)