1
1
import warnings
2
2
from abc import ABC
3
+ from collections import defaultdict
3
4
from typing import Any , Dict , List
4
5
5
6
@@ -8,14 +9,14 @@ class BaseHeadersSerializer(ABC):
8
9
Helper class to correctly serialize headers and cookies on the response payload.
9
10
"""
10
11
11
- def serialize (self , headers : Dict [str , str ], cookies : List [str ]) -> Dict [str , Any ]:
12
+ def serialize (self , headers : Dict [str , List [ str ] ], cookies : List [str ]) -> Dict [str , Any ]:
12
13
"""
13
14
Serializes headers and cookies according to the request type.
14
15
Returns a dict that can be merged with the response payload.
15
16
16
17
Parameters
17
18
----------
18
- headers: Dict[str, str]
19
+ headers: Dict[str, List[ str] ]
19
20
A dictionary of headers to set in the response
20
21
cookies: List[str]
21
22
A list of cookies to set in the response
@@ -24,7 +25,7 @@ def serialize(self, headers: Dict[str, str], cookies: List[str]) -> Dict[str, An
24
25
25
26
26
27
class HttpApiSerializer (BaseHeadersSerializer ):
27
- def serialize (self , headers : Dict [str , str ], cookies : List [str ]) -> Dict [str , Any ]:
28
+ def serialize (self , headers : Dict [str , List [ str ] ], cookies : List [str ]) -> Dict [str , Any ]:
28
29
"""
29
30
When using HTTP APIs or LambdaFunctionURLs, everything is taken care automatically for us.
30
31
We can directly assign a list of cookies and a dict of headers to the response payload, and the
@@ -33,11 +34,18 @@ def serialize(self, headers: Dict[str, str], cookies: List[str]) -> Dict[str, An
33
34
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format
34
35
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response
35
36
"""
36
- return {"headers" : headers , "cookies" : cookies }
37
+
38
+ # Format 2.0 doesn't have multiValueHeaders or multiValueQueryStringParameters fields.
39
+ # Duplicate headers are combined with commas and included in the headers field.
40
+ combined_headers : Dict [str , str ] = {}
41
+ for key , values in headers .items ():
42
+ combined_headers [key ] = "," .join (values )
43
+
44
+ return {"headers" : combined_headers , "cookies" : cookies }
37
45
38
46
39
47
class MultiValueHeadersSerializer (BaseHeadersSerializer ):
40
- def serialize (self , headers : Dict [str , str ], cookies : List [str ]) -> Dict [str , Any ]:
48
+ def serialize (self , headers : Dict [str , List [ str ] ], cookies : List [str ]) -> Dict [str , Any ]:
41
49
"""
42
50
When using REST APIs, headers can be encoded using the `multiValueHeaders` key on the response.
43
51
This is also the case when using an ALB integration with the `multiValueHeaders` option enabled.
@@ -46,10 +54,11 @@ def serialize(self, headers: Dict[str, str], cookies: List[str]) -> Dict[str, An
46
54
https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
47
55
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers-response
48
56
"""
49
- payload : Dict [str , List [str ]] = {}
57
+ payload : Dict [str , List [str ]] = defaultdict ( list )
50
58
51
- for key , value in headers .items ():
52
- payload [key ] = [value ]
59
+ for key , values in headers .items ():
60
+ for value in values :
61
+ payload [key ].append (value )
53
62
54
63
if cookies :
55
64
payload .setdefault ("Set-Cookie" , [])
@@ -60,7 +69,7 @@ def serialize(self, headers: Dict[str, str], cookies: List[str]) -> Dict[str, An
60
69
61
70
62
71
class SingleValueHeadersSerializer (BaseHeadersSerializer ):
63
- def serialize (self , headers : Dict [str , str ], cookies : List [str ]) -> Dict [str , Any ]:
72
+ def serialize (self , headers : Dict [str , List [ str ] ], cookies : List [str ]) -> Dict [str , Any ]:
64
73
"""
65
74
The ALB integration has `multiValueHeaders` disabled by default.
66
75
If we try to set multiple headers with the same key, or more than one cookie, print a warning.
@@ -80,7 +89,14 @@ def serialize(self, headers: Dict[str, str], cookies: List[str]) -> Dict[str, An
80
89
# We can only send one cookie, send the last one
81
90
payload ["headers" ]["Set-Cookie" ] = cookies [- 1 ]
82
91
83
- for key , value in headers .items ():
84
- payload ["headers" ][key ] = value
92
+ for key , values in headers .items ():
93
+ if len (values ) > 1 :
94
+ warnings .warn (
95
+ "Can't encode more than one header value for the same key in the response. "
96
+ "Did you enable multiValueHeaders on the ALB Target Group?"
97
+ )
98
+
99
+ # We can only set one header per key, send the last one
100
+ payload ["headers" ][key ] = values [- 1 ]
85
101
86
102
return payload
0 commit comments