Repository: litestar-org/litestar

Issue:
Bug: Header values should not be lowercased
**Describe the bug**
Headers keys and values are lowercased before being rendered. While lowercasing key is fine (as per HTTP2 spec), lowercasing values should not be done.

For my use case, integrating with a payment provider involves passing a transaction ID as a header. This ID contains lowercase, uppercase letters, and is not case-insensitive.

**To Reproduce**
1. Create a new route_handler.
2. In the route_handler, modify the response: `response.headers["Foo"] = "Bar"` .
3. Observe that the key and value are returned as lowercase:

![2022-10-27_16-23](https://user-images.githubusercontent.com/546693/198312809-fc5b8947-be88-4354-b909-033270ae188f.png)

4. While reporting this, I noticed that `date` and `vary` headers are not lowercased.

**Additional context**
Looking at the Git history, it seems that originally Starlette was used for handling the responses. I thought that Starlette might also have this behaviour, but they do not lowercase the header values. See https://github.com/encode/starlette/blob/fa737beb2838f568fe2477e2316a7fdf3d3eb257/starlette/responses.py#L72 .

The relevant code in Starlite is here: https://github.com/starlite-api/starlite/blob/95379f102be249f3c9453fbf9d216a41eede2d6f/starlite/response/base.py#L257



Discussion:
yup, will fix. @provinzkraut can you take this on quickly and add it to the release you are doing?
@Goldziher will do. Just waiting for a comment from you on the open conversations, then it's ready to go

Resolving patch:
diff --git a/starlite/response/base.py b/starlite/response/base.py
--- a/starlite/response/base.py
+++ b/starlite/response/base.py
@@ -255,7 +255,7 @@ def encoded_headers(self) -> List[Tuple[bytes, bytes]]:
             content_type = self.media_type
 
         encoded_headers = [
-            *((k.lower().encode("latin-1"), str(v).lower().encode("latin-1")) for k, v in self.headers.items()),
+            *((k.lower().encode("latin-1"), str(v).encode("latin-1")) for k, v in self.headers.items()),
             *((b"set-cookie", cookie.to_header(header="").encode("latin-1")) for cookie in self.cookies),
             (b"content-type", content_type.encode("latin-1")),
         ]


Test patch:
diff --git a/tests/response/test_base_response.py b/tests/response/test_base_response.py
--- a/tests/response/test_base_response.py
+++ b/tests/response/test_base_response.py
@@ -31,6 +31,18 @@ def handler() -> Response:
         assert response.headers["content-type"] == "text/plain; charset=utf-8"
 
 
+def test_response_headers_do_not_lowercase_values() -> None:
+    # reproduces: https://github.com/starlite-api/starlite/issues/693
+
+    @get("/")
+    def handler() -> Response:
+        return Response(content="hello world", media_type=MediaType.TEXT, headers={"foo": "BaR"})
+
+    with create_test_client(handler) as client:
+        response = client.get("/")
+        assert response.headers["foo"] == "BaR"
+
+
 def test_set_cookie() -> None:
     @get("/")
     def handler() -> Response:
diff --git a/tests/response/test_file_response.py b/tests/response/test_file_response.py
--- a/tests/response/test_file_response.py
+++ b/tests/response/test_file_response.py
@@ -79,7 +79,7 @@ def test_file_response_with_chinese_filename(tmpdir: Path) -> None:
     app = FileResponse(path=path, filename=filename)
     client = TestClient(app)
     response = client.get("/")
-    expected_disposition = "attachment; filename*=utf-8''%e4%bd%a0%e5%a5%bd.txt"
+    expected_disposition = "attachment; filename*=utf-8''%E4%BD%A0%E5%A5%BD.txt"
     assert response.status_code == HTTP_200_OK
     assert response.content == content
     assert response.headers["content-disposition"] == expected_disposition