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.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Singleton Headers (such as User-Agent) are separated at comma when using httpadapter.NewV2

hohmannr opened this issue · comments

Bug

Description

When using *httpadapter.HandlerAdapterV2 to proxy a events.APIGatewayV2HTTPRequest, single-value headers, such as User-Agent, Authorization, etc. which may contain commas in their value, are cut into multiple http.Header values when proxying. This leads to strange behaviour with methods like *http.Request.UserAgent(), which results in a cut-off User-Agent.

Reproduction

package main

import (
	"context"
	"fmt"
	"net/http"

	"github.com/aws/aws-lambda-go/events"
	"github.com/awslabs/aws-lambda-go-api-proxy/httpadapter"
)

func Example() {
	adapter := httpadapter.NewV2(http.HandlerFunc(handler))

	// User-Agent gets cut at its comma value
	adapter.ProxyWithContext(context.Background(), apiGatewayV2Request())
	// Output: User-Agent: Mozilla/5.0 (Linux; Android 11; Pixel 5 Build/RQ3A.210805.001.A1; wv) AppleWebKit/537.36 (KHTML
}

func apiGatewayV2Request() events.APIGatewayV2HTTPRequest {
	return events.APIGatewayV2HTTPRequest{
		Headers: map[string]string{
			// normal multi-valued header
			"Some-Multi-Value-Header": "value1,value2,value3",
			// singleton header (only a single value is allowed, which can be comma-separated)
			"User-Agent": "Mozilla/5.0 (Linux; Android 11; Pixel 5 Build/RQ3A.210805.001.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/92.0.4515.159 Mobile Safari/537.36",
		},
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("User-Agent: %s", r.UserAgent())

	w.WriteHeader(http.StatusOK)
}

Fix

Firstly, in *RequestAccessorV2.EventToRequest one should split the header fields into single-value (singleton) headers and multi-value capabale (multitons) headers. Then parse the singletons as a single value and the multitons as a comma separted list. This fix has been implemented, see !179. I have used
mozilla's list for singleton headers, as well as net/textproto.CanonicalMIMEHeaderKey to make the singleton-multiton-split case-insensitive. Test cases have also been added (disclaimer: its the first time for me to use ginkgo, hopefully what I did is correct).

I am noticing that the Stripe-Signature header is being truncated. I am still investigating. But it's happening in my golang Lambda with Fiber v2 and this adapter.

Stripe-Signature: t=1492774577,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd,v0=6ffbb59b2300aae63f272406069a9788598b792a944a07aba816edb039989a39

So, it the fix might not include this scenario.

Using
github.com/awslabs/aws-lambda-go-api-proxy v0.16.0

Confirmed by looking at the raw headers that Stripe-Signature was SPLIT into when using c.GetReqHeaders()

Stripe-Signature:[t=1702555126 v1=a9a17a234ecb883eda3863ba1aa2a19a1783a585dbac352c3e0194db6f16524e v0=a7f227f2366b925a99a278f9a972c69c3c85de2461b9b5b4dd1cf53e931a2ac1]

I can re-join for now, but this is still a bug then.