Repository: quarkusio/quarkus
Issue: Commas in Headers with AWS Lambda

### Describe the bug

When you are dealing with headers that can have commas in their value, such as Access-Control-Request-Headers, the Lambda Handler seems to interpret them as different header values which causes CORS to not work correctly.

### Expected behavior

When executing the curl
```
curl http://localhost:8080/hello -X OPTIONS -H 'Origin: http://example.com' -H 'Access-Control-Request-Headers: bar,foo' -v
```
the following header is returned
```
access-control-allow-headers: bar,foo
```

### Actual behavior

The following header is returned
```
access-control-allow-headers: bar
```

### How to Reproduce?

1. Generate a new quarkus project with "AWS Lambda HTTP" and "RestEasy Classic Jackson" extension
2. Add the following lines to the application.properties:
```
quarkus.http.cors=true
quarkus.http.cors.origins=http://example.com
```
3. Run ./mvnw quarkus:dev
4. Execute the curls given above
5. Uncomment the "quarkus-amazon-lambda-http" in the `pom.xml` to see the expected behaviour

### Output of `uname -a` or `ver`

Linux [REMOVED] 5.13.0-40-generic #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

### Output of `java -version`

openjdk version "14.0.2" 2020-07-14

### GraalVM version (if different from Java)

N/A, the issue can be reproduced without GraalVM

### Quarkus version or git rev

2.9.0.Final

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

Apache Maven 3.8.4

### Additional information

Event though the reproduction steps do not include deployment to Lambda, I have observed the same behavior with a different project also when it was deployed to AWS Lambda

In the `io.quarkus.vertx.http.runtime.cors.CORSFilter` class, only the first header value is retrieved in this line:
```
final String requestedHeaders = request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
```

But in the `io.quarkus.amazon.lambda.http.LambdaHttpHandler`, the string parts separated by comma are stored as different header values:
```
for (String val : header.getValue().split(","))
  nettyRequest.headers().add(header.getKey(), val);
```
This is probably necessary because the API Gateway will send multiple header values separated with comma and there is no way to reconstruct the original request from the API Gateway's event. Maybe it would be an acceptable solution to have the CORSFilter expect multiple header values

Changed files:
integration-tests/amazon-lambda-http/src/main/java/io/quarkus/it/amazon/lambda/GreetingResource.java
extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java
integration-tests/amazon-lambda-http/src/test/java/io/quarkus/it/amazon/lambda/AmazonLambdaSimpleTestCase.java

diff --git a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java
index dea92dbf76d..d407f0c3747 100644
--- a/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java
+++ b/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java
@@ -9,10 +9,12 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 
 import org.jboss.logging.Logger;
@@ -47,8 +49,13 @@ public class LambdaHttpHandler implements RequestHandler<APIGatewayV2HTTPEvent,
     private static final int BUFFER_SIZE = 8096;
 
     private static final Headers errorHeaders = new Headers();
+
+    // comma headers for headers that have comma in value and we don't want to split it up into
+    // multiple headers
+    private static final Set<String> commaHeaders = new HashSet();
     static {
         errorHeaders.putSingle("Content-Type", "application/json");
+        commaHeaders.add("access-control-request-headers");
     }
 
     public APIGatewayV2HTTPResponse handleRequest(APIGatewayV2HTTPEvent request, Context context) {
@@ -182,8 +189,14 @@ httpMethod, ofNullable(request.getRawQueryString())
         if (request.getHeaders() != null) { //apparently this can be null if no headers are sent
             for (Map.Entry<String, String> header : request.getHeaders().entrySet()) {
                 if (header.getValue() != null) {
-                    for (String val : header.getValue().split(","))
-                        nettyRequest.headers().add(header.getKey(), val);
+                    // Some header values have commas in them and we don't want to
+                    // split them up into multiple header values.
+                    if (commaHeaders.contains(header.getKey().toLowerCase(Locale.ROOT))) {
+                        nettyRequest.headers().add(header.getKey(), header.getValue());
+                    } else {
+                        for (String val : header.getValue().split(","))
+                            nettyRequest.headers().add(header.getKey(), val);
+                    }
                 }
             }
         }
diff --git a/integration-tests/amazon-lambda-http/src/main/java/io/quarkus/it/amazon/lambda/GreetingResource.java b/integration-tests/amazon-lambda-http/src/main/java/io/quarkus/it/amazon/lambda/GreetingResource.java
index 754f52d36f4..36a740f406d 100644
--- a/integration-tests/amazon-lambda-http/src/main/java/io/quarkus/it/amazon/lambda/GreetingResource.java
+++ b/integration-tests/amazon-lambda-http/src/main/java/io/quarkus/it/amazon/lambda/GreetingResource.java
@@ -3,6 +3,7 @@
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
@@ -14,6 +15,15 @@
 @Path("/hello")
 public class GreetingResource {
 
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @Path("comma")
+    public String comma(@HeaderParam("Access-Control-Request-Headers") String access) {
+        if (access == null || !access.contains(","))
+            throw new RuntimeException("should have comma");
+        return "ok";
+    }
+
     @GET
     @Produces(MediaType.TEXT_PLAIN)
     public String hello() {
diff --git a/integration-tests/amazon-lambda-http/src/test/java/io/quarkus/it/amazon/lambda/AmazonLambdaSimpleTestCase.java b/integration-tests/amazon-lambda-http/src/test/java/io/quarkus/it/amazon/lambda/AmazonLambdaSimpleTestCase.java
index dfc91d8cb9c..7fa451af996 100644
--- a/integration-tests/amazon-lambda-http/src/test/java/io/quarkus/it/amazon/lambda/AmazonLambdaSimpleTestCase.java
+++ b/integration-tests/amazon-lambda-http/src/test/java/io/quarkus/it/amazon/lambda/AmazonLambdaSimpleTestCase.java
@@ -22,6 +22,16 @@
 @QuarkusTest
 public class AmazonLambdaSimpleTestCase {
 
+    @Test
+    public void testComma() throws Exception {
+        given()
+                .when()
+                .header("Access-Control-Request-Headers", "foo, bar, yello")
+                .get("/hello/comma")
+                .then()
+                .statusCode(200);
+    }
+
     @Test
     public void testContext() throws Exception {
         given()