Skip to content

juliusz-cwiakalski/example-bug-quarkus-aws-lambda-gateway-v2-multiple-cookies-broken

Repository files navigation

Summary

When using Quarkus as an AWS Lambda handler behind API Gateway v2, multiple Set-Cookie headers are incorrectly merged into a single header in the Lambda response. This causes browsers to fail to set multiple cookies as expected, breaking applications that rely on more than one cookie.

Steps to Reproduce

  1. Build the Lambda function:

    ./gradlew build -Dquarkus.package.jar.enabled=true -Dquarkus.package.jar.type=legacy-jar -Dquarkus.native.enabled=false
  2. Invoke the Lambda function locally:

    sam local invoke --template ./build/sam.jvm.yaml -e ./example-gateway-event.json
  3. (Optional) Debug:

    sam local invoke --template ./build/sam.jvm.yaml -e ./example-gateway-event.json --debug-port 5858 

    Then connect your IDE to localhost:5858.

Actual Behavior

The response from PingController merges all cookies into a single Set-Cookie header:

{
  "statusCode": 200,
  "headers": {
    "content-length": "40",
    "Set-Cookie": "cookie1=value1;Version=1;Path=/;Max-Age=3600;Secure;HttpOnly;SameSite=Lax,cookie2=value2;Version=1;Path=/;Max-Age=3600;Secure;HttpOnly;SameSite=Lax",
    "Content-Type": "application/json"
  },
  "multiValueHeaders": null,
  "cookies": null,
  "body": "{\"status\":\"ok\",\"rootPath\":\"Hello hello\"}",
  "isBase64Encoded": false
}

As a result, when deployed to AWS, browsers do not set multiple cookies correctly if more than one is present.

Expected Behavior

The response should use the cookies array field as per API Gateway v2 Lambda integration, with each cookie as a separate entry:

{
  "statusCode": 200,
  "headers": {
    "content-length": "40",
    "Content-Type": "application/json"
  },
  "multiValueHeaders": null,
  "cookies": [
    "cookie1=value1;Version=1;Path=/;Max-Age=3600;Secure;HttpOnly;SameSite=Lax",
    "cookie2=value2;Version=1;Path=/;Max-Age=3600;Secure;HttpOnly;SameSite=Lax"
  ],
  "body": "{\"status\":\"ok\",\"rootPath\":\"Hello hello\"}",
  "isBase64Encoded": false
}

With this format, browsers correctly set multiple cookies.

Root Cause Analysis

The bug is caused by the following logic in LambdaHttpHandler:

// Handle cookies separately to preserve commas in the header values
@Override
public void handleMessage(Object msg) {
    try {
        // ...existing code...
        if (msg instanceof HttpResponse res) {
            responseBuilder.setStatusCode(res.status().code());
            final Map<String, String> headers = new HashMap<>();
            responseBuilder.setHeaders(headers);
            for (String name : res.headers().names()) {
                final List<String> allForName = res.headers().getAll(name);
                if (allForName == null || allForName.isEmpty()) {
                    continue;
                }
                // Handle cookies separately to preserve commas in the header values
                if ("set-cookie".equals(name)) {
                    responseBuilder.setCookies(allForName);
                    continue;
                }
                // ...
            }
        }
    }
}

However, in the Lambda runtime context, the msg is of type io.vertx.core.http.impl.AssembledFullHttpResponse, and its headers are an instance of io.vertx.core.http.impl.headers.HeadersMultiMap, which is case-insensitive and converts all header names to Camel-Kebab-Case. Thus, the check for "set-cookie" fails because the actual header name is "Set-Cookie".

Solution

Change the header name check to be case-insensitive:

if ("set-cookie".equalsIgnoreCase(name)) {
    responseBuilder.setCookies(allForName);
    continue;
}

References


This bug report was generated from a minimal reproduction project: example-bug-quarkus-aws-lambda-gateway-v2-multiple-cookies-broken

About

Example project demonstrating a bug in Quarkus AWS lambda extension

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages