diff --git a/rolo/serving/twisted.py b/rolo/serving/twisted.py index 2ae1f25..5209664 100644 --- a/rolo/serving/twisted.py +++ b/rolo/serving/twisted.py @@ -221,8 +221,9 @@ def writeHeaders( else: # newer twisted versions instead pass the headers object for name, values in headers.getAllRawHeaders(): - line = name + b": " + b",".join(values) + b"\r\n" - headerSequence.append(line) + for value in values: + line = name + b": " + value + b"\r\n" + headerSequence.append(line) headerSequence.append(b"\r\n") self.transport.writeSequence(headerSequence) diff --git a/tests/gateway/test_headers.py b/tests/gateway/test_headers.py index 8e62d69..deaa3cf 100644 --- a/tests/gateway/test_headers.py +++ b/tests/gateway/test_headers.py @@ -1,4 +1,6 @@ +import http.client import json +from collections import defaultdict import pytest import requests @@ -14,6 +16,8 @@ def handler(chain: HandlerChain, context: RequestContext, response: Response): response.mimetype = "application/json" response.headers["X-fOO_bar"] = "FooBar" response.headers["content-md5"] = "af5e58f9a7c4682e1b410f2e9392a539" + response.headers.add("multi-value", "value1") + response.headers.add("multi-value", "value2") return response gateway = Gateway(request_handlers=[handler]) @@ -39,3 +43,31 @@ def handler(chain: HandlerChain, context: RequestContext, response: Response): assert "X-fOO_bar" in response_headers # even though it's a standard header, it should be in the original case assert "content-md5" in response_headers + assert response_headers["multi-value"] == "value1, value2" + + +@pytest.mark.parametrize("serve_gateway", ["asgi", "twisted"], indirect=True) +def test_multivalue_header_handling(serve_gateway): + def handler(chain: HandlerChain, context: RequestContext, response: Response): + response.data = json.dumps({"headers": dict(context.request.headers)}) + response.mimetype = "application/json" + response.headers.add("multi-value", "value1") + response.headers.add("multi-value", "value2") + return response + + gateway = Gateway(request_handlers=[handler]) + + srv = serve_gateway(gateway) + + # we need to use a low level HTTP client because `requests` does some header manipulation and concatenation which + # obscures the behavior + conn = http.client.HTTPConnection(host="127.0.0.1", port=srv.port) + + conn.request("GET", url="/hello") + response = conn.getresponse() + response_headers = defaultdict(list) + + for k, v in response.headers.items(): + response_headers[k].append(v) + + assert response_headers["multi-value"] == ["value1", "value2"]