0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-22 11:17:33 +01:00

fix(adapter): handle multi value headers in AWS Lambda (#2494)

* Headers can be undefined on ALB

* Delegate headers from multiValueHeaders

* Add test

* Assert header values

* format

* Make multiValueHeaders optional so it can be omitted

* Avoid Object.entries when undefined

* Write tests in runtime_tests
This commit is contained in:
TATSUNO “Taz” Yasuhiro 2024-04-18 08:13:37 +09:00 committed by GitHub
parent 932307efd8
commit acb56b8d30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 117 additions and 5 deletions

View File

@ -139,6 +139,13 @@ describe('AWS Lambda Adapter for Hono', () => {
return c.text('Valid Cookies')
})
app.post('/headers', (c) => {
if (c.req.header('foo')?.includes('bar')) {
return c.json({ message: 'ok' })
}
return c.json({ message: 'fail' }, 400)
})
const handler = handle(app)
const testApiGatewayRequestContext = {
@ -491,6 +498,100 @@ describe('AWS Lambda Adapter for Hono', () => {
])
})
describe('headers', () => {
describe('single-value headers', () => {
it('Should extract single-value headers and return 200 (ALBProxyEvent)', async () => {
const event = {
body: '{}',
httpMethod: 'POST',
isBase64Encoded: false,
path: '/headers',
headers: {
host: 'localhost',
foo: 'bar',
},
requestContext: testALBRequestContext,
}
const apiGatewayResponseV2 = await handler(event)
expect(apiGatewayResponseV2.statusCode).toBe(200)
})
it('Should extract single-value headers and return 200 (APIGatewayProxyEvent)', async () => {
const apigatewayProxyEvent = {
version: '1.0',
resource: '/headers',
httpMethod: 'POST',
headers: {
host: 'localhost',
foo: 'bar',
},
path: '/headers',
body: null,
isBase64Encoded: false,
requestContext: testApiGatewayRequestContext,
}
const apiGatewayResponseV2 = await handler(apigatewayProxyEvent)
expect(apiGatewayResponseV2.statusCode).toBe(200)
})
it('Should extract single-value headers and return 200 (APIGatewayProxyEventV2)', async () => {
const apigatewayProxyV2Event = {
version: '2.0',
routeKey: '$default',
headers: {
host: 'localhost',
foo: 'bar',
},
rawPath: '/headers',
rawQueryString: '',
requestContext: testApiGatewayRequestContextV2,
resource: '/headers',
body: null,
isBase64Encoded: false,
}
const apiGatewayResponseV2 = await handler(apigatewayProxyV2Event)
expect(apiGatewayResponseV2.statusCode).toBe(200)
})
})
describe('multi-value headers', () => {
it('Should extract multi-value headers and return 200 (ALBProxyEvent)', async () => {
const event = {
body: '{}',
httpMethod: 'POST',
isBase64Encoded: false,
path: '/headers',
multiValueHeaders: {
host: ['localhost'],
foo: ['bar'],
},
requestContext: testALBRequestContext,
}
const apiGatewayResponseV2 = await handler(event)
expect(apiGatewayResponseV2.statusCode).toBe(200)
})
it('Should extract multi-value headers and return 200 (APIGatewayProxyEvent)', async () => {
const apigatewayProxyEvent = {
version: '1.0',
resource: '/headers',
httpMethod: 'POST',
headers: {},
multiValueHeaders: {
host: ['localhost'],
foo: ['bar'],
},
path: '/headers',
body: null,
isBase64Encoded: false,
requestContext: testApiGatewayRequestContext,
}
const apiGatewayResponseV2 = await handler(apigatewayProxyEvent)
expect(apiGatewayResponseV2.statusCode).toBe(200)
})
})
})
it('Should handle a POST request and return a 200 response if cookies match (APIGatewayProxyEvent V1 and V2)', async () => {
const apiGatewayEvent = {
version: '1.0',

View File

@ -22,6 +22,7 @@ export interface APIGatewayProxyEventV2 {
version: string
routeKey: string
headers: Record<string, string | undefined>
multiValueHeaders?: undefined
cookies?: string[]
rawPath: string
rawQueryString: string
@ -63,7 +64,8 @@ export interface APIGatewayProxyEvent {
// When calling Lambda through an Application Load Balancer
export interface ALBProxyEvent {
httpMethod: string
headers: Record<string, string | undefined>
headers?: Record<string, string | undefined>
multiValueHeaders?: Record<string, string[] | undefined>
path: string
body: string | null
isBase64Encoded: boolean
@ -198,16 +200,25 @@ const createRequest = (event: LambdaEvent) => {
const domainName =
event.requestContext && 'domainName' in event.requestContext
? event.requestContext.domainName
: event.headers['host']
: event.headers?.['host'] ?? event.multiValueHeaders?.['host']?.[0]
const path = isProxyEventV2(event) ? event.rawPath : event.path
const urlPath = `https://${domainName}${path}`
const url = queryString ? `${urlPath}?${queryString}` : urlPath
const headers = new Headers()
getCookies(event, headers)
for (const [k, v] of Object.entries(event.headers)) {
if (v) {
headers.set(k, v)
if (event.headers) {
for (const [k, v] of Object.entries(event.headers)) {
if (v) {
headers.set(k, v)
}
}
}
if (event.multiValueHeaders) {
for (const [k, values] of Object.entries(event.multiValueHeaders)) {
if (values) {
values.forEach((v) => headers.append(k, v))
}
}
}