Skip to content

Commit 646615c

Browse files
koxudaxikhamaileon
authored andcommitted
Support multiValueHeaders on Response (Kludex#129)
* support multiValueHeaders
1 parent 0136417 commit 646615c

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

mangum/protocols/http.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,23 @@ async def send(self, message: Message) -> None:
115115
and message_type == "http.response.start"
116116
):
117117
self.response["statusCode"] = message["status"]
118-
self.response["headers"] = {
119-
k.decode().lower(): v.decode() for k, v in message.get("headers", [])
120-
}
118+
headers: typing.Dict[str, str] = {}
119+
multi_value_headers: typing.Dict[str, typing.List[str]] = {}
120+
for key, value in message.get("headers", []):
121+
lower_key = key.decode().lower()
122+
if lower_key in multi_value_headers:
123+
multi_value_headers[lower_key].append(value.decode())
124+
elif lower_key in headers:
125+
multi_value_headers[lower_key] = [
126+
headers.pop(lower_key),
127+
value.decode(),
128+
]
129+
else:
130+
headers[lower_key] = value.decode()
131+
132+
self.response["headers"] = headers
133+
if multi_value_headers:
134+
self.response["multiValueHeaders"] = multi_value_headers
121135
self.state = HTTPCycleState.RESPONSE
122136

123137
elif (

tests/test_http.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,3 +682,57 @@ async def app(scope, receive, send):
682682
"headers": {"content-type": "text/plain; charset=utf-8"},
683683
"body": "Hello, world!",
684684
}
685+
686+
687+
@pytest.mark.parametrize(
688+
"mock_http_event,response_headers,expected_headers,expected_multi_value_headers",
689+
[
690+
[
691+
["GET", None, None],
692+
[[b"key1", b"value1"], [b"key2", b"value2"]],
693+
{"key1": "value1", "key2": "value2"},
694+
{},
695+
],
696+
[
697+
["GET", None, None],
698+
[[b"key1", b"value1"], [b"key1", b"value2"]],
699+
{},
700+
{"key1": ["value1", "value2"]},
701+
],
702+
[
703+
["GET", None, None],
704+
[[b"key1", b"value1"], [b"key1", b"value2"], [b"key1", b"value3"]],
705+
{},
706+
{"key1": ["value1", "value2", "value3"]},
707+
],
708+
[["GET", None, None], [], {}, {}],
709+
],
710+
indirect=["mock_http_event"],
711+
)
712+
def test_http_response_headers(
713+
mock_http_event, response_headers, expected_headers, expected_multi_value_headers
714+
) -> None:
715+
async def app(scope, receive, send):
716+
await send(
717+
{
718+
"type": "http.response.start",
719+
"status": 200,
720+
"headers": [[b"content-type", b"text/plain; charset=utf-8"]]
721+
+ response_headers,
722+
}
723+
)
724+
await send({"type": "http.response.body", "body": b"Hello, world!"})
725+
726+
handler = Mangum(app, lifespan="off")
727+
response = handler(mock_http_event, {})
728+
expected = {
729+
"statusCode": 200,
730+
"isBase64Encoded": False,
731+
"headers": {"content-type": "text/plain; charset=utf-8"},
732+
"body": "Hello, world!",
733+
}
734+
if expected_headers:
735+
expected["headers"].update(expected_headers)
736+
if expected_multi_value_headers:
737+
expected["multiValueHeaders"] = expected_multi_value_headers
738+
assert response == expected

0 commit comments

Comments
 (0)