Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

headers and multiValueHeaders are not set properly when using hono/aws-lambda with ALB #2626

Closed
yiss opened this issue May 6, 2024 · 7 comments
Labels

Comments

@yiss
Copy link
Contributor

yiss commented May 6, 2024

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-lambdaadapter 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

Screenshot 2024-05-06 at 20 00 17

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 the event.cookies value as string
  • Solution 2: When multiValueHeaders is present, pass to it all the values from headers 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.

@yiss yiss added the bug label May 6, 2024
@yusukebe
Copy link
Member

yusukebe commented May 6, 2024

Hi @yiss

Now #2585 is merged. Is this problem still occurring with it?

@yiss
Copy link
Contributor Author

yiss commented May 6, 2024

@yusukebe I haven't seen this change. I'm going to test it and report back

@yiss
Copy link
Contributor Author

yiss commented May 6, 2024

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
Copy link
Member

yusukebe commented May 7, 2024

@yiss

Thank you for confirming. Can you create a PR to fix it?

@yiss
Copy link
Contributor Author

yiss commented May 7, 2024

@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 ?

@yusukebe
Copy link
Member

yusukebe commented May 7, 2024

@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? ^

@watany-dev
Copy link
Contributor

This approach looks good.

adding an albProcessor to seperate the ALB behavior from the API Gateway for the multiHeadersValue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants