awslabs / aws-lambda-go-api-proxy

lambda-go-api-proxy makes it easy to port APIs written with Go frameworks such as Gin (https://gin-gonic.github.io/gin/ ) to AWS Lambda and Amazon API Gateway.
Apache License 2.0
1.04k stars 197 forks source link

HTTP API's collate headers and multivalueheaders for duplicate responses #75

Open krotscheck opened 4 years ago

krotscheck commented 4 years ago

So, here's a doozy bug that I encountered using the Gateway HTTP API (the new version) and the events returned from this proxy, that results in the duplication of headers. The process is this:

1. I attach a location header to my response

rw.Header().Set("Location", location)

2. The following event is produced by the go-api-proxy

{
    "statusCode": 201,
    "headers": {
        "Location": "my-location"
    },
    "multiValueHeaders": {
        "Location": [
            "my-location"
        ]
    },
    "body": ""
}

3. Duplicated headers received by the client

So far so good, right? Well, it turns out that the HTTP response that the client receives looks like this:

apigw-requestid: R4j5hhzBvHcEJ4w=
content-length: 0
date: Wed, 26 Aug 2020 15:31:10 GMT
location: my-location
location: my-location
status: 201

A bit more investigation, and I discovered that the HTTP API Gateway event translation merges the responses from both 'headers' and 'multiValueHeaders', creating the above multi-header response. Now, the multiple location headers are, strictly speaking, valid HTTP. However, according to the docs:

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.

Workaround

The simplest workaround is to add an event interceptor in golang that deletes either of the two header blocks before returning it. Or, well, merge #73

sylvain101010 commented 4 years ago

I confirm this annoying bug.

charlietran commented 4 years ago

This bug is happening to me as well. Thank you for filing this issue @krotscheck and making this Google-able :)

Fixing it as such in our HTTP handler until this gets handled upstream:

func main() {
    lambda.Start(handler)
}

func handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    // httpLambda is an instance of aws-lambda-go-api-proxy/httpadapter
    resp, err := httpLambda.ProxyWithContext(ctx, req)
    resp.Headers = nil
    return resp, err
}
sapessi commented 3 years ago

I've tagged v0.8.1 that includes this fix. I'll keep this issue open as we investigate with the API Gateway team.