From 447d9fb0c877100109536d82c9925f5a23b1b741 Mon Sep 17 00:00:00 2001 From: fluxth Date: Fri, 17 May 2024 10:11:17 +0900 Subject: [PATCH] fix: return correct header keys for each integration (#877) Each integration handle header keys differently, this patch tries to address these differences so that we have proper headers in responses. **ALB Integration** https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers-response The names of the fields used for headers differ depending on whether you enable multi-value headers for the target group. You must use multiValueHeaders if you have enabled multi-value headers and headers otherwise. **APIGW v1 Integration** https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format If you specify values for both headers and multiValueHeaders, API Gateway merges them into a single list. If the same key-value pair is specified in both, only the values from multiValueHeaders will appear in the merged list. **APIGW v2 Integration** https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html Format 2.0 doesn't have multiValueHeaders or multiValueQueryStringParameters fields. Duplicate headers are combined with commas and included in the headers field. Duplicate query strings are combined with commas and included in the queryStringParameters field. **`awslabs/aws-lambda-go-api-proxy` source code** - https://github.com/awslabs/aws-lambda-go-api-proxy/blob/3f6c8160ae0c22b0bd05b2e3a9122736f035c74b/core/response.go#L117 - https://github.com/awslabs/aws-lambda-go-api-proxy/blob/3f6c8160ae0c22b0bd05b2e3a9122736f035c74b/core/responseALB.go#L108 - https://github.com/awslabs/aws-lambda-go-api-proxy/blob/3f6c8160ae0c22b0bd05b2e3a9122736f035c74b/core/responsev2.go#L117 --- lambda-http/src/response.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lambda-http/src/response.rs b/lambda-http/src/response.rs index c1b48ef2..6a31cb79 100644 --- a/lambda-http/src/response.rs +++ b/lambda-http/src/response.rs @@ -69,8 +69,8 @@ impl LambdaResponse { body, is_base64_encoded, status_code: status_code as i64, - // explicitly empty, as API gateway does not properly merge headers and - // multi-value-headers, resulting in duplicate headers + // Explicitly empty, as API gateway v1 will merge "headers" and + // "multi_value_headers" fields together resulting in duplicate response headers. headers: HeaderMap::new(), multi_value_headers: headers, }), @@ -93,10 +93,10 @@ impl LambdaResponse { is_base64_encoded, status_code: status_code as i64, cookies, - // explicitly empty, as API gateway does not properly merge headers and - // multi-value-headers, resulting in duplicate headers - headers: HeaderMap::new(), - multi_value_headers: headers, + // API gateway v2 doesn't have "multi_value_headers" field. Duplicate headers + // are combined with commas and included in the headers field. + headers, + multi_value_headers: HeaderMap::new(), }) } #[cfg(feature = "alb")] @@ -104,10 +104,9 @@ impl LambdaResponse { body, status_code: status_code as i64, is_base64_encoded, - // ALB responses are used for ALB integrations as well as - // Lambda Function URLs. The former uses the `multi_value_headers` field, - // while the later uses the `headers` field. We need to return - // both fields to ensure both integrations work correctly. + // ALB responses are used for ALB integration, which can be configured to use + // either "headers" or "multi_value_headers" field. We need to return both fields + // to ensure both configuration work correctly. headers: headers.clone(), multi_value_headers: headers, status_description: Some(format!( @@ -121,8 +120,8 @@ impl LambdaResponse { body, is_base64_encoded, status_code: status_code as i64, - // explicitly empty, as API gateway does not properly merge headers and - // multi-value-headers, resulting in duplicate headers + // Explicitly empty, as API gateway v1 will merge "headers" and + // "multi_value_headers" fields together resulting in duplicate response headers. headers: HeaderMap::new(), multi_value_headers: headers, }), @@ -475,7 +474,7 @@ mod tests { let json = serde_json::to_string(&response).expect("failed to serialize to json"); assert_eq!( json, - r#"{"statusCode":200,"headers":{},"multiValueHeaders":{"content-encoding":["gzip"]},"body":"MDAwMDAw","isBase64Encoded":true,"cookies":[]}"# + r#"{"statusCode":200,"headers":{"content-encoding":"gzip"},"multiValueHeaders":{},"body":"MDAwMDAw","isBase64Encoded":true,"cookies":[]}"# ) } @@ -493,7 +492,7 @@ mod tests { let json = serde_json::to_string(&response).expect("failed to serialize to json"); assert_eq!( json, - r#"{"statusCode":200,"headers":{},"multiValueHeaders":{"content-type":["application/json"]},"body":"000000","isBase64Encoded":false,"cookies":[]}"# + r#"{"statusCode":200,"headers":{"content-type":"application/json"},"multiValueHeaders":{},"body":"000000","isBase64Encoded":false,"cookies":[]}"# ) } @@ -511,7 +510,7 @@ mod tests { let json = serde_json::to_string(&response).expect("failed to serialize to json"); assert_eq!( json, - r#"{"statusCode":200,"headers":{},"multiValueHeaders":{"content-type":["application/json; charset=utf-16"]},"body":"〰〰〰","isBase64Encoded":false,"cookies":[]}"# + r#"{"statusCode":200,"headers":{"content-type":"application/json; charset=utf-16"},"multiValueHeaders":{},"body":"〰〰〰","isBase64Encoded":false,"cookies":[]}"# ) } @@ -529,7 +528,7 @@ mod tests { let json = serde_json::to_string(&response).expect("failed to serialize to json"); assert_eq!( json, - r#"{"statusCode":200,"headers":{},"multiValueHeaders":{"content-type":["application/graphql-response+json; charset=utf-16"]},"body":"〰〰〰","isBase64Encoded":false,"cookies":[]}"# + r#"{"statusCode":200,"headers":{"content-type":"application/graphql-response+json; charset=utf-16"},"multiValueHeaders":{},"body":"〰〰〰","isBase64Encoded":false,"cookies":[]}"# ) }