`headers` and `multiValueHeaders` are not set properly when using `hono/aws-lambda` with ALB
Closed this issue · 7 comments
What version of Hono are you using?
^4.3.2
What runtime/platform is your app running on?
Node, AWS Lambda
What steps can reproduce the bug?
When using hono/aws-lambda
adapter with a Lambda that has an ALB in front of it. It shouldn't use the multiValueHeaders
as default, as this feature is not default when using ALB with Lambda target. Moreover, the set-cookie
behavior in the adapter might result in bugs in some cases.
Example :
import { handle } from "hono/aws-lambda";
import { getCookie, setCookie } from "hono/cookie";
import { Hono } from "hono";
const app = new Hono();
app.get("/set-headers", (ctx) => {
setCookie(ctx, "foo", "bar", {
secure: process.env.NODE_ENV === "production",
domain: `.${process.env.COOKIE_DOMAINE}`,
httpOnly: true,
maxAge: 60 * 10,
sameSite: "Lax",
});
setCookie(ctx, "fizz", "buzz", {
secure: process.env.NODE_ENV === "production",
domain: `.${process.env.COOKIE_DOMAINE}`,
httpOnly: true,
maxAge: 60 * 10,
sameSite: "Lax",
});
return ctx.redirect("/get-headers");
});
app.get("/get-headers", (ctx) => {
const fooCookie = getCookie(ctx, "foo");
const fizzCookie = getCookie(ctx, "fizz");
return ctx.json({
fooCookie,
fizzCookie,
});
});
export const handler = handle(app);
And CDK minimal config :
import * as cdk from '@aws-cdk/core';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as lambda from '@aws-cdk/aws-lambda';
import * as lambdaNodejs from '@aws-cdk/aws-lambda-nodejs';
import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2';
export class CdkAlbLambdaStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Create VPC
const vpc = new ec2.Vpc(this, 'MyVpc', {
maxAzs: 2
});
// Create Lambda function
const lambdaFunction = new lambdaNodejs.NodejsFunction(this, 'MyLambda', {
entry: 'lambda/index.ts', // Entry file for your Lambda function
handler: 'handler', // Exported function name in your entry file
});
// Target Groupe
const targetGroup = new elbv2.ApplicationTargetGroup(
this,
`${name}-target-group`,
{
vpc: this.alb.vpc,
targetType: elbv2.TargetType.LAMBDA,
targets: [new elbv2Targets.LambdaTarget(lambdaFunction)],
}
);
// Create ALB
const alb = new elbv2.ApplicationLoadBalancer(this, 'MyAlb', {
vpc,
internetFacing: true
});
const albCert = new acm.Certificate(this, "alb-cert", {
domainName: `${hostedZoneName}`,
validation: acm.CertificateValidation.fromDns(hostedZone),
});
const listener = alb.addListener("alb-http-listener", {
port: 80,
open: true,
});
// Create ALB Listener
// Add Lambda as a target to ALB Listener
listener.addTargets('LambdaTarget', {
port: 80,
targets: [targetGroup],
});
}
}
As I mentioned before the multiValueHeaders
is not enabled by default, to enable it we must add the following
...
targetGroup.setAttribute("lambda.multi_value_headers.enabled", "true");
...
But when this behavior is enabled, the ALB will ignore the headers
value and only take multiHeadersValue
except in Hono adapter not all the headers are propagated from headers
to multiValueHeaders
. Disabling the multiValueHeaders
will result in set-cookie
being passed as an array so the ALB will only take the last value
Here is the result payload of the example with multiValueHeaders
enabled :
{
"result": {
"body": "",
"headers": {
"access-control-allow-origin": "*",
"content-type": "text/plain;charset=UTF-8",
"location": "/get-headers"
},
"statusCode": 302,
"isBase64Encoded": false,
"multiValueHeaders": {
"set-cookie": [
"foo=bar; Max-Age=600; Domain=.mydomaine.com; Path=/; HttpOnly; SameSite=Lax",
"fizz=buzz; Max-Age=600; Domain=.mydomaine.com; Path=/; HttpOnly; SameSite=Lax"
]
}
}
}
More info from AWS website : https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers
What is the expected behavior?
Two solution are possible :
- Soluion 1: When the
set-cookie
is available, and it's an array, flatten it and put it directly in theevent.cookies
value as string - Solution 2: When
multiValueHeaders
is present, pass to it all the values fromheaders
as well
What do you see instead?
No response
Additional information
I would love to contribute and create a PR for the fix. I have managed to create a wrapper around handle
function for internal testing purposes.
Yes I can confirm that it's still happening. It seems that ALB straight out ignores the headers if multiValueHeaders is present in the response
@yusukebe I will raise the PR soon. I was thinking of adding an albProcessor to seperate the ALB behavior from the API Gateway for the multiHeadersValue. Any thoughts? Or should I just put the the change in createResult and createRequest ?
@yiss Thank you.
I was thinking of adding an albProcessor to seperate the ALB behavior from the API Gateway for the multiHeadersValue. Any thoughts? Or should I just put the the change in createResult and createRequest ?
@watany-dev Do you have any advance? ^
This approach looks good.
adding an albProcessor to seperate the ALB behavior from the API Gateway for the multiHeadersValue.