github twitter linkedin email rss
GoLang: Case-sensitive HTTP Headers with net/http
Aug 11, 2016
2 minutes read

Today, Amazon Web Services released a number of updates to their services. In particular, they added a feature to API Gateway called Usage Plans. Unfortunately, it seems that they’ve introduced a change that is not backwards compatible with previous versions of the service.

API Gateway allows the use of api key authentication. The keys are to be passed in using an HTTP header named x-api-key. Previously, the casing in this header didn’t matter. x-api-key, X-Api-Key, and X-API-KEY were all treated the same. However, after the recent changes, API Gateway seems to only accept x-api-key.

This is especially frustrating for applications using Go’s http.Client which is part of the Go standard libary net/http. The following code snippet can be used to add the x-api-key header to a request:

client := &http.Client{}
request, _ := http.NewRequest("GET", "https://someapi/someresource", nil)
request.Header.Set("x-api-key", "somelongapikey2349208759283")
response, _ := client.Do(request)

However, request.Header.Set(...) ends up calling CanonicalMIMEHeaderKey on the header key, in this case "x-api-key". This converts "x-api-key" to "X-Api-Key". Note that request.Header.Add("x-api-key", "somelongapikey2349208759283") does the same thing. While this is good behavior on Go’s part, we need this header to be all lowercase.

So how can we set a header to be all lowercase? It turns out that request.Header is an alias of the type map[string][]string. Thus, we can set the header key as lowercase (or whatever we want) with the following code:

client := &http.Client{}
request, _ := http.NewRequest("GET", "https://someapi/someresource", nil)
r.Header["x-api-key"] = []string{ "somelongapikey2349208759283" }
response, _ := client.Do(request)

tl;dr; AWS released a backwards-incompatible change to an API that requires a lowercase HTTP header. The Go Standard Library converts headers to canonical format.

UPDATE: Reddit user /u/mwholt pointed out that this might have to do with HTTP/2 requiring lowercase header fields.

UPDATE 2: It appears that AWS has fixed the issue with API Gateway.

Back to posts