Skip to content

Commit

Permalink
fix(aws-lambda): avoid duplicating already set headers (#2585)
Browse files Browse the repository at this point in the history
* fix: avoid duplicating already set headers

* test: add missing content-type header
  • Loading branch information
Amorim33 authored May 6, 2024
1 parent 4cd2dff commit c95e135
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 3 deletions.
142 changes: 141 additions & 1 deletion src/adapter/aws-lambda/handler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isContentTypeBinary, isContentEncodingBinary } from './handler'
import type { LambdaEvent } from './handler'
import { getProcessor, isContentEncodingBinary, isContentTypeBinary } from './handler'

describe('isContentTypeBinary', () => {
it('Should determine whether it is binary', () => {
Expand Down Expand Up @@ -27,3 +28,142 @@ describe('isContentEncodingBinary', () => {
expect(isContentEncodingBinary('unknown')).toBe(false)
})
})

describe('EventProcessor.createRequest', () => {
it('Should return valid Request object from version 1.0 API Gateway event', () => {
const event: LambdaEvent = {
version: '1.0',
resource: '/my/path',
path: '/my/path',
httpMethod: 'GET',
headers: {
'content-type': 'application/json',
header1: 'value1',
header2: 'value1',
},
multiValueHeaders: {
header1: ['value1'],
header2: ['value1', 'value2', 'value3'],
},
queryStringParameters: {
parameter2: 'value',
},
multiValueQueryStringParameters: {
parameter1: ['value1', 'value2'],
parameter2: ['value'],
},
requestContext: {
accountId: '123456789012',
apiId: 'id',
authorizer: {
claims: null,
scopes: null,
},
domainName: 'id.execute-api.us-east-1.amazonaws.com',
domainPrefix: 'id',
extendedRequestId: 'request-id',
httpMethod: 'GET',
identity: {
sourceIp: '192.0.2.1',
userAgent: 'user-agent',
clientCert: {
clientCertPem: 'CERT_CONTENT',
subjectDN: 'www.example.com',
issuerDN: 'Example issuer',
serialNumber: 'a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1',
validity: {
notBefore: 'May 28 12:30:02 2019 GMT',
notAfter: 'Aug 5 09:36:04 2021 GMT',
},
},
},
path: '/my/path',
protocol: 'HTTP/1.1',
requestId: 'id=',
requestTime: '04/Mar/2020:19:15:17 +0000',
requestTimeEpoch: 1583349317135,
resourcePath: '/my/path',
stage: '$default',
},
pathParameters: {},
stageVariables: {},
body: null,
isBase64Encoded: false,
}

const processor = getProcessor(event)
const request = processor.createRequest(event)

expect(request.method).toEqual('GET')
expect(request.url).toEqual(
'https://id.execute-api.us-east-1.amazonaws.com/my/path?parameter2=value'
)
expect(Object.fromEntries(request.headers)).toEqual({
'content-type': 'application/json',
header1: 'value1',
header2: 'value1, value2, value3',
})
})

it('Should return valid Request object from version 2.0 API Gateway event', () => {
const event: LambdaEvent = {
version: '2.0',
routeKey: '$default',
rawPath: '/my/path',
rawQueryString: 'parameter1=value1&parameter1=value2&parameter2=value',
cookies: ['cookie1', 'cookie2'],
headers: {
'content-type': 'application/json',
header1: 'value1',
header2: 'value1,value2',
},
queryStringParameters: {
parameter1: 'value1,value2',
parameter2: 'value',
},
requestContext: {
accountId: '123456789012',
apiId: 'api-id',
authentication: null,
authorizer: {},
domainName: 'id.execute-api.us-east-1.amazonaws.com',
domainPrefix: 'id',
http: {
method: 'POST',
path: '/my/path',
protocol: 'HTTP/1.1',
sourceIp: '192.0.2.1',
userAgent: 'agent',
},
requestId: 'id',
routeKey: '$default',
stage: '$default',
time: '12/Mar/2020:19:03:58 +0000',
timeEpoch: 1583348638390,
},
body: 'Hello from Lambda',
pathParameters: {
parameter1: 'value1',
},
isBase64Encoded: false,
stageVariables: {
stageVariable1: 'value1',
stageVariable2: 'value2',
},
}

const processor = getProcessor(event)
const request = processor.createRequest(event)

expect(request.method).toEqual('POST')
expect(request.url).toEqual(
'https://id.execute-api.us-east-1.amazonaws.com/my/path?parameter1=value1&parameter1=value2&parameter2=value'
)
expect(Object.fromEntries(request.headers)).toEqual({
'content-type': 'application/json',
cookie: 'cookie1; cookie2',
header1: 'value1',
header2: 'value1,value2',
})
})
})
6 changes: 4 additions & 2 deletions src/adapter/aws-lambda/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,9 @@ abstract class EventProcessor<E extends LambdaEvent> {
if (event.multiValueHeaders) {
for (const [k, values] of Object.entries(event.multiValueHeaders)) {
if (values) {
values.forEach((v) => headers.append(k, v))
// avoid duplicating already set headers
const foundK = headers.get(k)
values.forEach((v) => (!foundK || !foundK.includes(v)) && headers.append(k, v))
}
}
}
Expand Down Expand Up @@ -318,7 +320,7 @@ const v1Processor = new (class EventV1Processor extends EventProcessor<
}
})()

const getProcessor = (event: LambdaEvent): EventProcessor<LambdaEvent> => {
export const getProcessor = (event: LambdaEvent): EventProcessor<LambdaEvent> => {
if (isProxyEventV2(event)) {
return v2Processor
} else {
Expand Down

0 comments on commit c95e135

Please sign in to comment.