Repository: encode/starlette

Issue:
Content-Type and Content-Length headers not automatically populated if headers is given
Hi! I was playing around with responses and stumbled upon what seems like a bug. I have already pushed a [fix](https://github.com/florimondmanca/starlette/commit/e6dc80d203b613f211003df63352a37550538e9a) on my fork and would be happy to open a PR. :)

---

**Expected behavior**
If the `headers` dictionary passed to `Response` does not contain the `Content-Type` or `Content-Length` headers, the resulting response should populate automatically said headers based on the given `media_type` and `content`.

**Actual behavior**
The `Content-Type` and `Content-Length` headers are not set.

**To reproduce**
```python
from starlette.responses import Response
from starlette.testclient import TestClient

def app(scope):
    return Response(content="hi", headers={}, media_type="text/plain")

client = TestClient(app)
response = client.get("/")
assert response.headers["content-length"] == "2"  # fails: KeyError
assert response.headers["content-type"] == "text/plain; charset=utf-8"  # fails: KeyError
```

**Possible solutions**
After inspecting the code in [responses.py], there seems to be a logical fallacy:
```python
if headers is None:
    # ...
else:
    raw_headers = [...]
    keys = [h[0] for h in raw_headers]
    populate_content_length = b"content-length" in keys  # (*)
    populate_content_type = b"content-type" in keys  # (*)
```

Lines (*) (66 and 67) mean that the headers are populate if they are *already* present in `headers`. They should be populated if they are *not* present => switching to `not in keys` there should fix the bug.

**Specs**

- macOS 10.12
- Python 3.7.1
- Starlette@master


Discussion:

Patch:
diff --git a/starlette/responses.py b/starlette/responses.py
index 542e800..3b8d275 100644
--- a/starlette/responses.py
+++ b/starlette/responses.py
@@ -63,8 +63,8 @@ class Response:
                 for k, v in headers.items()
             ]
             keys = [h[0] for h in raw_headers]
-            populate_content_length = b"content-length" in keys
-            populate_content_type = b"content-type" in keys
+            populate_content_length = b"content-length" not in keys
+            populate_content_type = b"content-type" not in keys
 
         body = getattr(self, "body", b"")
         if body and populate_content_length:


Test patch:
diff --git a/tests/test_responses.py b/tests/test_responses.py
index 0b79051..d4bafaf 100644
--- a/tests/test_responses.py
+++ b/tests/test_responses.py
@@ -275,3 +275,15 @@ def test_template_response():
 def test_template_response_requires_request():
     with pytest.raises(ValueError):
         TemplateResponse(None, {})
+
+
+def test_populate_headers():
+    def app(scope):
+        headers = {}
+        return Response(content="hi", headers=headers, media_type="text/html")
+
+    client = TestClient(app)
+    response = client.get("/")
+    assert response.text == "hi"
+    assert response.headers["content-length"] == "2"
+    assert response.headers["content-type"] == "text/html; charset=utf-8"