I believe I found an issue in the CORS middleware when using multiple origin hostnames:
I have looked into it (code is here: https://github.com/middyjs/middy/blob/master/src/middlewares/cors.js#L11) and see that the middleware looks if handler.event.headers.Origin is in the list of origins in the options object. However, in my lambda I notice that the property name is actually origin - lowercase. The middleware then defaults the return value to the first value in the list - making it work at least half of the time ;)
This is the event I'm looking at in my lambda:
{
"resource": "/<my-lambda-name>",
"path": "/<my-lambda-name>",
"httpMethod": "POST",
"headers": {
"accept": "application/json, text/plain, */*",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9,nl;q=0.8,la;q=0.7",
"cache-control": "no-cache",
"content-type": "application/json;charset=UTF-8",
"Host": "cvncasbjtj.execute-api.eu-central-1.amazonaws.com",
"origin": "http://localhost:9000",
"pragma": "no-cache",
"referer": "http://localhost:9000/",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-5c0460a8-439ab6d017dfffc05eec1c90",
"X-Forwarded-For": "<my-ip>",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
(...redacted for brevity...)
"body": "<my request body>",
"isBase64Encoded": false
}
It's likely API Gateway + HTTP2 related.
HTTP/2 encodes HTTP headers as lowercase. HTTP/1.1 headers were already case-insensitive, but not everbody adhered to that rule.
source: https://evertpot.com/http-2-finalized
The serverless framework is currently working through the same issue https://github.com/serverless/serverless/issues/2765
It would be quite easy to come up with a fix for this problem within the CORS middleware itself. Is this something I can help with?
While I was writing the above, I was thinking that it would probably be better if it was possible to do some normalisation on the headers passed to the lambda function instead of normalising it case-by-case in the middlewares themselves. Turns out that already exists: https://github.com/middyjs/middy/blob/master/src/middlewares/httpHeaderNormalizer.js 馃憤
Adding this middleware before CORS solves my problem.
Perhaps a better idea then to suggest using these two middlewares together in the docs!
I suggest using caseless to navigate properties in caseless way.
This line fails if event.headers contains 'content-type'.
This works regardless of cases.
const headers = caseless(event.headers)
if (headers.has['Content-Type']) {
...
}
Most helpful comment
It would be quite easy to come up with a fix for this problem within the CORS middleware itself. Is this something I can help with?While I was writing the above, I was thinking that it would probably be better if it was possible to do some normalisation on the headers passed to the lambda function instead of normalising it case-by-case in the middlewares themselves. Turns out that already exists: https://github.com/middyjs/middy/blob/master/src/middlewares/httpHeaderNormalizer.js 馃憤
Adding this middleware before CORS solves my problem.
Perhaps a better idea then to suggest using these two middlewares together in the docs!