We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `starlette/responses.py`
Content:
```
1 import hashlib
2 import http.cookies
3 import json
4 import os
5 import stat
6 import typing
7 from email.utils import formatdate
8 from mimetypes import guess_type
9 from urllib.parse import quote_plus
10 
11 from starlette.background import BackgroundTask
12 from starlette.datastructures import URL, MutableHeaders
13 from starlette.types import Receive, Send
14 
15 try:
16     import aiofiles
17     from aiofiles.os import stat as aio_stat
18 except ImportError:  # pragma: nocover
19     aiofiles = None  # type: ignore
20     aio_stat = None  # type: ignore
21 
22 try:
23     import ujson
24 except ImportError:  # pragma: nocover
25     ujson = None  # type: ignore
26 
27 
28 class Response:
29     media_type = None
30     charset = "utf-8"
31 
32     def __init__(
33         self,
34         content: typing.Any = None,
35         status_code: int = 200,
36         headers: dict = None,
37         media_type: str = None,
38         background: BackgroundTask = None,
39     ) -> None:
40         if content is None:
41             self.body = b""
42         else:
43             self.body = self.render(content)
44         self.status_code = status_code
45         if media_type is not None:
46             self.media_type = media_type
47         self.background = background
48         self.init_headers(headers)
49 
50     def render(self, content: typing.Any) -> bytes:
51         if isinstance(content, bytes):
52             return content
53         return content.encode(self.charset)
54 
55     def init_headers(self, headers: typing.Mapping[str, str] = None) -> None:
56         if headers is None:
57             raw_headers = []  # type: typing.List[typing.Tuple[bytes, bytes]]
58             populate_content_length = True
59             populate_content_type = True
60         else:
61             raw_headers = [
62                 (k.lower().encode("latin-1"), v.encode("latin-1"))
63                 for k, v in headers.items()
64             ]
65             keys = [h[0] for h in raw_headers]
66             populate_content_length = b"content-length" in keys
67             populate_content_type = b"content-type" in keys
68 
69         body = getattr(self, "body", b"")
70         if body and populate_content_length:
71             content_length = str(len(body))
72             raw_headers.append((b"content-length", content_length.encode("latin-1")))
73 
74         content_type = self.media_type
75         if content_type is not None and populate_content_type:
76             if content_type.startswith("text/"):
77                 content_type += "; charset=" + self.charset
78             raw_headers.append((b"content-type", content_type.encode("latin-1")))
79 
80         self.raw_headers = raw_headers
81 
82     @property
83     def headers(self) -> MutableHeaders:
84         if not hasattr(self, "_headers"):
85             self._headers = MutableHeaders(raw=self.raw_headers)
86         return self._headers
87 
88     def set_cookie(
89         self,
90         key: str,
91         value: str = "",
92         max_age: int = None,
93         expires: int = None,
94         path: str = "/",
95         domain: str = None,
96         secure: bool = False,
97         httponly: bool = False,
98     ) -> None:
99         cookie = http.cookies.SimpleCookie()
100         cookie[key] = value
101         if max_age is not None:
102             cookie[key]["max-age"] = max_age  # type: ignore
103         if expires is not None:
104             cookie[key]["expires"] = expires  # type: ignore
105         if path is not None:
106             cookie[key]["path"] = path
107         if domain is not None:
108             cookie[key]["domain"] = domain
109         if secure:
110             cookie[key]["secure"] = True  # type: ignore
111         if httponly:
112             cookie[key]["httponly"] = True  # type: ignore
113         cookie_val = cookie.output(header="").strip()
114         self.raw_headers.append((b"set-cookie", cookie_val.encode("latin-1")))
115 
116     def delete_cookie(self, key: str, path: str = "/", domain: str = None) -> None:
117         self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain)
118 
119     async def __call__(self, receive: Receive, send: Send) -> None:
120         await send(
121             {
122                 "type": "http.response.start",
123                 "status": self.status_code,
124                 "headers": self.raw_headers,
125             }
126         )
127         await send({"type": "http.response.body", "body": self.body})
128 
129         if self.background is not None:
130             await self.background()
131 
132 
133 class HTMLResponse(Response):
134     media_type = "text/html"
135 
136 
137 class PlainTextResponse(Response):
138     media_type = "text/plain"
139 
140 
141 class TemplateResponse(Response):
142     media_type = "text/html"
143 
144     def __init__(
145         self,
146         template: typing.Any,
147         context: dict,
148         status_code: int = 200,
149         headers: dict = None,
150         media_type: str = None,
151         background: BackgroundTask = None,
152     ):
153         if "request" not in context:
154             raise ValueError('context must include a "request" key')
155         self.template = template
156         self.context = context
157         content = template.render(context)
158         super().__init__(content, status_code, headers, media_type, background)
159 
160     async def __call__(self, receive: Receive, send: Send) -> None:
161         request = self.context["request"]
162         extensions = request.get("extensions", {})
163         if "http.response.template" in extensions:
164             await send(
165                 {
166                     "type": "http.response.template",
167                     "template": self.template,
168                     "context": self.context,
169                 }
170             )
171         await super().__call__(receive, send)
172 
173 
174 class JSONResponse(Response):
175     media_type = "application/json"
176 
177     def render(self, content: typing.Any) -> bytes:
178         return json.dumps(
179             content,
180             ensure_ascii=False,
181             allow_nan=False,
182             indent=None,
183             separators=(",", ":"),
184         ).encode("utf-8")
185 
186 
187 class UJSONResponse(JSONResponse):
188     media_type = "application/json"
189 
190     def render(self, content: typing.Any) -> bytes:
191         return ujson.dumps(content, ensure_ascii=False).encode("utf-8")
192 
193 
194 class RedirectResponse(Response):
195     def __init__(
196         self, url: typing.Union[str, URL], status_code: int = 302, headers: dict = None
197     ) -> None:
198         super().__init__(content=b"", status_code=status_code, headers=headers)
199         self.headers["location"] = quote_plus(str(url), safe=":/#?&=@[]!$&'()*+,;")
200 
201 
202 class StreamingResponse(Response):
203     def __init__(
204         self,
205         content: typing.Any,
206         status_code: int = 200,
207         headers: dict = None,
208         media_type: str = None,
209         background: BackgroundTask = None,
210     ) -> None:
211         self.body_iterator = content
212         self.status_code = status_code
213         self.media_type = self.media_type if media_type is None else media_type
214         self.background = background
215         self.init_headers(headers)
216 
217     async def __call__(self, receive: Receive, send: Send) -> None:
218         await send(
219             {
220                 "type": "http.response.start",
221                 "status": self.status_code,
222                 "headers": self.raw_headers,
223             }
224         )
225         async for chunk in self.body_iterator:
226             if not isinstance(chunk, bytes):
227                 chunk = chunk.encode(self.charset)
228             await send({"type": "http.response.body", "body": chunk, "more_body": True})
229         await send({"type": "http.response.body", "body": b"", "more_body": False})
230 
231         if self.background is not None:
232             await self.background()
233 
234 
235 class FileResponse(Response):
236     chunk_size = 4096
237 
238     def __init__(
239         self,
240         path: str,
241         headers: dict = None,
242         media_type: str = None,
243         background: BackgroundTask = None,
244         filename: str = None,
245         stat_result: os.stat_result = None,
246         method: str = None,
247     ) -> None:
248         assert aiofiles is not None, "'aiofiles' must be installed to use FileResponse"
249         self.path = path
250         self.status_code = 200
251         self.filename = filename
252         self.send_header_only = method is not None and method.upper() == "HEAD"
253         if media_type is None:
254             media_type = guess_type(filename or path)[0] or "text/plain"
255         self.media_type = media_type
256         self.background = background
257         self.init_headers(headers)
258         if self.filename is not None:
259             content_disposition = 'attachment; filename="{}"'.format(self.filename)
260             self.headers.setdefault("content-disposition", content_disposition)
261         self.stat_result = stat_result
262         if stat_result is not None:
263             self.set_stat_headers(stat_result)
264 
265     @classmethod
266     def get_stat_headers(cls, stat_result: os.stat_result) -> typing.Dict[str, str]:
267         content_length = str(stat_result.st_size)
268         last_modified = formatdate(stat_result.st_mtime, usegmt=True)
269         etag_base = str(stat_result.st_mtime) + "-" + str(stat_result.st_size)
270         etag = hashlib.md5(etag_base.encode()).hexdigest()
271         return {
272             "content-length": content_length,
273             "last-modified": last_modified,
274             "etag": etag,
275         }
276 
277     def set_stat_headers(self, stat_result: os.stat_result) -> None:
278         stat_headers = self.get_stat_headers(stat_result)
279         for name, value in stat_headers.items():
280             self.headers.setdefault(name, value)
281 
282     async def __call__(self, receive: Receive, send: Send) -> None:
283         if self.stat_result is None:
284             try:
285                 stat_result = await aio_stat(self.path)
286                 self.set_stat_headers(stat_result)
287             except FileNotFoundError:
288                 raise RuntimeError(f"File at path {self.path} does not exist.")
289             else:
290                 mode = stat_result.st_mode
291                 if not stat.S_ISREG(mode):
292                     raise RuntimeError(f"File at path {self.path} is not a file.")
293         await send(
294             {
295                 "type": "http.response.start",
296                 "status": self.status_code,
297                 "headers": self.raw_headers,
298             }
299         )
300         if self.send_header_only:
301             await send({"type": "http.response.body"})
302         else:
303             async with aiofiles.open(self.path, mode="rb") as file:
304                 more_body = True
305                 while more_body:
306                     chunk = await file.read(self.chunk_size)
307                     more_body = len(chunk) == self.chunk_size
308                     await send(
309                         {
310                             "type": "http.response.body",
311                             "body": chunk,
312                             "more_body": more_body,
313                         }
314                     )
315         if self.background is not None:
316             await self.background()
317
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/starlette/responses.py b/starlette/responses.py
--- a/starlette/responses.py
+++ b/starlette/responses.py
@@ -63,8 +63,8 @@
                 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:

{"golden_diff": "diff --git a/starlette/responses.py b/starlette/responses.py\n--- a/starlette/responses.py\n+++ b/starlette/responses.py\n@@ -63,8 +63,8 @@\n                 for k, v in headers.items()\n             ]\n             keys = [h[0] for h in raw_headers]\n-            populate_content_length = b\"content-length\" in keys\n-            populate_content_type = b\"content-type\" in keys\n+            populate_content_length = b\"content-length\" not in keys\n+            populate_content_type = b\"content-type\" not in keys\n \n         body = getattr(self, \"body\", b\"\")\n         if body and populate_content_length:\n", "issue": "Content-Type and Content-Length headers not automatically populated if headers is given\nHi! 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. :)\r\n\r\n---\r\n\r\n**Expected behavior**\r\nIf 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`.\r\n\r\n**Actual behavior**\r\nThe `Content-Type` and `Content-Length` headers are not set.\r\n\r\n**To reproduce**\r\n```python\r\nfrom starlette.responses import Response\r\nfrom starlette.testclient import TestClient\r\n\r\ndef app(scope):\r\n    return Response(content=\"hi\", headers={}, media_type=\"text/plain\")\r\n\r\nclient = TestClient(app)\r\nresponse = client.get(\"/\")\r\nassert response.headers[\"content-length\"] == \"2\"  # fails: KeyError\r\nassert response.headers[\"content-type\"] == \"text/plain; charset=utf-8\"  # fails: KeyError\r\n```\r\n\r\n**Possible solutions**\r\nAfter inspecting the code in [responses.py], there seems to be a logical fallacy:\r\n```python\r\nif headers is None:\r\n    # ...\r\nelse:\r\n    raw_headers = [...]\r\n    keys = [h[0] for h in raw_headers]\r\n    populate_content_length = b\"content-length\" in keys  # (*)\r\n    populate_content_type = b\"content-type\" in keys  # (*)\r\n```\r\n\r\nLines (*) (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.\r\n\r\n**Specs**\r\n\r\n- macOS 10.12\r\n- Python 3.7.1\r\n- Starlette@master\r\n\n", "before_files": [{"content": "import hashlib\nimport http.cookies\nimport json\nimport os\nimport stat\nimport typing\nfrom email.utils import formatdate\nfrom mimetypes import guess_type\nfrom urllib.parse import quote_plus\n\nfrom starlette.background import BackgroundTask\nfrom starlette.datastructures import URL, MutableHeaders\nfrom starlette.types import Receive, Send\n\ntry:\n    import aiofiles\n    from aiofiles.os import stat as aio_stat\nexcept ImportError:  # pragma: nocover\n    aiofiles = None  # type: ignore\n    aio_stat = None  # type: ignore\n\ntry:\n    import ujson\nexcept ImportError:  # pragma: nocover\n    ujson = None  # type: ignore\n\n\nclass Response:\n    media_type = None\n    charset = \"utf-8\"\n\n    def __init__(\n        self,\n        content: typing.Any = None,\n        status_code: int = 200,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n    ) -> None:\n        if content is None:\n            self.body = b\"\"\n        else:\n            self.body = self.render(content)\n        self.status_code = status_code\n        if media_type is not None:\n            self.media_type = media_type\n        self.background = background\n        self.init_headers(headers)\n\n    def render(self, content: typing.Any) -> bytes:\n        if isinstance(content, bytes):\n            return content\n        return content.encode(self.charset)\n\n    def init_headers(self, headers: typing.Mapping[str, str] = None) -> None:\n        if headers is None:\n            raw_headers = []  # type: typing.List[typing.Tuple[bytes, bytes]]\n            populate_content_length = True\n            populate_content_type = True\n        else:\n            raw_headers = [\n                (k.lower().encode(\"latin-1\"), v.encode(\"latin-1\"))\n                for k, v in headers.items()\n            ]\n            keys = [h[0] for h in raw_headers]\n            populate_content_length = b\"content-length\" in keys\n            populate_content_type = b\"content-type\" in keys\n\n        body = getattr(self, \"body\", b\"\")\n        if body and populate_content_length:\n            content_length = str(len(body))\n            raw_headers.append((b\"content-length\", content_length.encode(\"latin-1\")))\n\n        content_type = self.media_type\n        if content_type is not None and populate_content_type:\n            if content_type.startswith(\"text/\"):\n                content_type += \"; charset=\" + self.charset\n            raw_headers.append((b\"content-type\", content_type.encode(\"latin-1\")))\n\n        self.raw_headers = raw_headers\n\n    @property\n    def headers(self) -> MutableHeaders:\n        if not hasattr(self, \"_headers\"):\n            self._headers = MutableHeaders(raw=self.raw_headers)\n        return self._headers\n\n    def set_cookie(\n        self,\n        key: str,\n        value: str = \"\",\n        max_age: int = None,\n        expires: int = None,\n        path: str = \"/\",\n        domain: str = None,\n        secure: bool = False,\n        httponly: bool = False,\n    ) -> None:\n        cookie = http.cookies.SimpleCookie()\n        cookie[key] = value\n        if max_age is not None:\n            cookie[key][\"max-age\"] = max_age  # type: ignore\n        if expires is not None:\n            cookie[key][\"expires\"] = expires  # type: ignore\n        if path is not None:\n            cookie[key][\"path\"] = path\n        if domain is not None:\n            cookie[key][\"domain\"] = domain\n        if secure:\n            cookie[key][\"secure\"] = True  # type: ignore\n        if httponly:\n            cookie[key][\"httponly\"] = True  # type: ignore\n        cookie_val = cookie.output(header=\"\").strip()\n        self.raw_headers.append((b\"set-cookie\", cookie_val.encode(\"latin-1\")))\n\n    def delete_cookie(self, key: str, path: str = \"/\", domain: str = None) -> None:\n        self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        await send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": self.status_code,\n                \"headers\": self.raw_headers,\n            }\n        )\n        await send({\"type\": \"http.response.body\", \"body\": self.body})\n\n        if self.background is not None:\n            await self.background()\n\n\nclass HTMLResponse(Response):\n    media_type = \"text/html\"\n\n\nclass PlainTextResponse(Response):\n    media_type = \"text/plain\"\n\n\nclass TemplateResponse(Response):\n    media_type = \"text/html\"\n\n    def __init__(\n        self,\n        template: typing.Any,\n        context: dict,\n        status_code: int = 200,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n    ):\n        if \"request\" not in context:\n            raise ValueError('context must include a \"request\" key')\n        self.template = template\n        self.context = context\n        content = template.render(context)\n        super().__init__(content, status_code, headers, media_type, background)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        request = self.context[\"request\"]\n        extensions = request.get(\"extensions\", {})\n        if \"http.response.template\" in extensions:\n            await send(\n                {\n                    \"type\": \"http.response.template\",\n                    \"template\": self.template,\n                    \"context\": self.context,\n                }\n            )\n        await super().__call__(receive, send)\n\n\nclass JSONResponse(Response):\n    media_type = \"application/json\"\n\n    def render(self, content: typing.Any) -> bytes:\n        return json.dumps(\n            content,\n            ensure_ascii=False,\n            allow_nan=False,\n            indent=None,\n            separators=(\",\", \":\"),\n        ).encode(\"utf-8\")\n\n\nclass UJSONResponse(JSONResponse):\n    media_type = \"application/json\"\n\n    def render(self, content: typing.Any) -> bytes:\n        return ujson.dumps(content, ensure_ascii=False).encode(\"utf-8\")\n\n\nclass RedirectResponse(Response):\n    def __init__(\n        self, url: typing.Union[str, URL], status_code: int = 302, headers: dict = None\n    ) -> None:\n        super().__init__(content=b\"\", status_code=status_code, headers=headers)\n        self.headers[\"location\"] = quote_plus(str(url), safe=\":/#?&=@[]!$&'()*+,;\")\n\n\nclass StreamingResponse(Response):\n    def __init__(\n        self,\n        content: typing.Any,\n        status_code: int = 200,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n    ) -> None:\n        self.body_iterator = content\n        self.status_code = status_code\n        self.media_type = self.media_type if media_type is None else media_type\n        self.background = background\n        self.init_headers(headers)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        await send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": self.status_code,\n                \"headers\": self.raw_headers,\n            }\n        )\n        async for chunk in self.body_iterator:\n            if not isinstance(chunk, bytes):\n                chunk = chunk.encode(self.charset)\n            await send({\"type\": \"http.response.body\", \"body\": chunk, \"more_body\": True})\n        await send({\"type\": \"http.response.body\", \"body\": b\"\", \"more_body\": False})\n\n        if self.background is not None:\n            await self.background()\n\n\nclass FileResponse(Response):\n    chunk_size = 4096\n\n    def __init__(\n        self,\n        path: str,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n        filename: str = None,\n        stat_result: os.stat_result = None,\n        method: str = None,\n    ) -> None:\n        assert aiofiles is not None, \"'aiofiles' must be installed to use FileResponse\"\n        self.path = path\n        self.status_code = 200\n        self.filename = filename\n        self.send_header_only = method is not None and method.upper() == \"HEAD\"\n        if media_type is None:\n            media_type = guess_type(filename or path)[0] or \"text/plain\"\n        self.media_type = media_type\n        self.background = background\n        self.init_headers(headers)\n        if self.filename is not None:\n            content_disposition = 'attachment; filename=\"{}\"'.format(self.filename)\n            self.headers.setdefault(\"content-disposition\", content_disposition)\n        self.stat_result = stat_result\n        if stat_result is not None:\n            self.set_stat_headers(stat_result)\n\n    @classmethod\n    def get_stat_headers(cls, stat_result: os.stat_result) -> typing.Dict[str, str]:\n        content_length = str(stat_result.st_size)\n        last_modified = formatdate(stat_result.st_mtime, usegmt=True)\n        etag_base = str(stat_result.st_mtime) + \"-\" + str(stat_result.st_size)\n        etag = hashlib.md5(etag_base.encode()).hexdigest()\n        return {\n            \"content-length\": content_length,\n            \"last-modified\": last_modified,\n            \"etag\": etag,\n        }\n\n    def set_stat_headers(self, stat_result: os.stat_result) -> None:\n        stat_headers = self.get_stat_headers(stat_result)\n        for name, value in stat_headers.items():\n            self.headers.setdefault(name, value)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        if self.stat_result is None:\n            try:\n                stat_result = await aio_stat(self.path)\n                self.set_stat_headers(stat_result)\n            except FileNotFoundError:\n                raise RuntimeError(f\"File at path {self.path} does not exist.\")\n            else:\n                mode = stat_result.st_mode\n                if not stat.S_ISREG(mode):\n                    raise RuntimeError(f\"File at path {self.path} is not a file.\")\n        await send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": self.status_code,\n                \"headers\": self.raw_headers,\n            }\n        )\n        if self.send_header_only:\n            await send({\"type\": \"http.response.body\"})\n        else:\n            async with aiofiles.open(self.path, mode=\"rb\") as file:\n                more_body = True\n                while more_body:\n                    chunk = await file.read(self.chunk_size)\n                    more_body = len(chunk) == self.chunk_size\n                    await send(\n                        {\n                            \"type\": \"http.response.body\",\n                            \"body\": chunk,\n                            \"more_body\": more_body,\n                        }\n                    )\n        if self.background is not None:\n            await self.background()\n", "path": "starlette/responses.py"}], "after_files": [{"content": "import hashlib\nimport http.cookies\nimport json\nimport os\nimport stat\nimport typing\nfrom email.utils import formatdate\nfrom mimetypes import guess_type\nfrom urllib.parse import quote_plus\n\nfrom starlette.background import BackgroundTask\nfrom starlette.datastructures import URL, MutableHeaders\nfrom starlette.types import Receive, Send\n\ntry:\n    import aiofiles\n    from aiofiles.os import stat as aio_stat\nexcept ImportError:  # pragma: nocover\n    aiofiles = None  # type: ignore\n    aio_stat = None  # type: ignore\n\ntry:\n    import ujson\nexcept ImportError:  # pragma: nocover\n    ujson = None  # type: ignore\n\n\nclass Response:\n    media_type = None\n    charset = \"utf-8\"\n\n    def __init__(\n        self,\n        content: typing.Any = None,\n        status_code: int = 200,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n    ) -> None:\n        if content is None:\n            self.body = b\"\"\n        else:\n            self.body = self.render(content)\n        self.status_code = status_code\n        if media_type is not None:\n            self.media_type = media_type\n        self.background = background\n        self.init_headers(headers)\n\n    def render(self, content: typing.Any) -> bytes:\n        if isinstance(content, bytes):\n            return content\n        return content.encode(self.charset)\n\n    def init_headers(self, headers: typing.Mapping[str, str] = None) -> None:\n        if headers is None:\n            raw_headers = []  # type: typing.List[typing.Tuple[bytes, bytes]]\n            populate_content_length = True\n            populate_content_type = True\n        else:\n            raw_headers = [\n                (k.lower().encode(\"latin-1\"), v.encode(\"latin-1\"))\n                for k, v in headers.items()\n            ]\n            keys = [h[0] for h in raw_headers]\n            populate_content_length = b\"content-length\" not in keys\n            populate_content_type = b\"content-type\" not in keys\n\n        body = getattr(self, \"body\", b\"\")\n        if body and populate_content_length:\n            content_length = str(len(body))\n            raw_headers.append((b\"content-length\", content_length.encode(\"latin-1\")))\n\n        content_type = self.media_type\n        if content_type is not None and populate_content_type:\n            if content_type.startswith(\"text/\"):\n                content_type += \"; charset=\" + self.charset\n            raw_headers.append((b\"content-type\", content_type.encode(\"latin-1\")))\n\n        self.raw_headers = raw_headers\n\n    @property\n    def headers(self) -> MutableHeaders:\n        if not hasattr(self, \"_headers\"):\n            self._headers = MutableHeaders(raw=self.raw_headers)\n        return self._headers\n\n    def set_cookie(\n        self,\n        key: str,\n        value: str = \"\",\n        max_age: int = None,\n        expires: int = None,\n        path: str = \"/\",\n        domain: str = None,\n        secure: bool = False,\n        httponly: bool = False,\n    ) -> None:\n        cookie = http.cookies.SimpleCookie()\n        cookie[key] = value\n        if max_age is not None:\n            cookie[key][\"max-age\"] = max_age  # type: ignore\n        if expires is not None:\n            cookie[key][\"expires\"] = expires  # type: ignore\n        if path is not None:\n            cookie[key][\"path\"] = path\n        if domain is not None:\n            cookie[key][\"domain\"] = domain\n        if secure:\n            cookie[key][\"secure\"] = True  # type: ignore\n        if httponly:\n            cookie[key][\"httponly\"] = True  # type: ignore\n        cookie_val = cookie.output(header=\"\").strip()\n        self.raw_headers.append((b\"set-cookie\", cookie_val.encode(\"latin-1\")))\n\n    def delete_cookie(self, key: str, path: str = \"/\", domain: str = None) -> None:\n        self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        await send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": self.status_code,\n                \"headers\": self.raw_headers,\n            }\n        )\n        await send({\"type\": \"http.response.body\", \"body\": self.body})\n\n        if self.background is not None:\n            await self.background()\n\n\nclass HTMLResponse(Response):\n    media_type = \"text/html\"\n\n\nclass PlainTextResponse(Response):\n    media_type = \"text/plain\"\n\n\nclass TemplateResponse(Response):\n    media_type = \"text/html\"\n\n    def __init__(\n        self,\n        template: typing.Any,\n        context: dict,\n        status_code: int = 200,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n    ):\n        if \"request\" not in context:\n            raise ValueError('context must include a \"request\" key')\n        self.template = template\n        self.context = context\n        content = template.render(context)\n        super().__init__(content, status_code, headers, media_type, background)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        request = self.context[\"request\"]\n        extensions = request.get(\"extensions\", {})\n        if \"http.response.template\" in extensions:\n            await send(\n                {\n                    \"type\": \"http.response.template\",\n                    \"template\": self.template,\n                    \"context\": self.context,\n                }\n            )\n        await super().__call__(receive, send)\n\n\nclass JSONResponse(Response):\n    media_type = \"application/json\"\n\n    def render(self, content: typing.Any) -> bytes:\n        return json.dumps(\n            content,\n            ensure_ascii=False,\n            allow_nan=False,\n            indent=None,\n            separators=(\",\", \":\"),\n        ).encode(\"utf-8\")\n\n\nclass UJSONResponse(JSONResponse):\n    media_type = \"application/json\"\n\n    def render(self, content: typing.Any) -> bytes:\n        return ujson.dumps(content, ensure_ascii=False).encode(\"utf-8\")\n\n\nclass RedirectResponse(Response):\n    def __init__(\n        self, url: typing.Union[str, URL], status_code: int = 302, headers: dict = None\n    ) -> None:\n        super().__init__(content=b\"\", status_code=status_code, headers=headers)\n        self.headers[\"location\"] = quote_plus(str(url), safe=\":/#?&=@[]!$&'()*+,;\")\n\n\nclass StreamingResponse(Response):\n    def __init__(\n        self,\n        content: typing.Any,\n        status_code: int = 200,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n    ) -> None:\n        self.body_iterator = content\n        self.status_code = status_code\n        self.media_type = self.media_type if media_type is None else media_type\n        self.background = background\n        self.init_headers(headers)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        await send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": self.status_code,\n                \"headers\": self.raw_headers,\n            }\n        )\n        async for chunk in self.body_iterator:\n            if not isinstance(chunk, bytes):\n                chunk = chunk.encode(self.charset)\n            await send({\"type\": \"http.response.body\", \"body\": chunk, \"more_body\": True})\n        await send({\"type\": \"http.response.body\", \"body\": b\"\", \"more_body\": False})\n\n        if self.background is not None:\n            await self.background()\n\n\nclass FileResponse(Response):\n    chunk_size = 4096\n\n    def __init__(\n        self,\n        path: str,\n        headers: dict = None,\n        media_type: str = None,\n        background: BackgroundTask = None,\n        filename: str = None,\n        stat_result: os.stat_result = None,\n        method: str = None,\n    ) -> None:\n        assert aiofiles is not None, \"'aiofiles' must be installed to use FileResponse\"\n        self.path = path\n        self.status_code = 200\n        self.filename = filename\n        self.send_header_only = method is not None and method.upper() == \"HEAD\"\n        if media_type is None:\n            media_type = guess_type(filename or path)[0] or \"text/plain\"\n        self.media_type = media_type\n        self.background = background\n        self.init_headers(headers)\n        if self.filename is not None:\n            content_disposition = 'attachment; filename=\"{}\"'.format(self.filename)\n            self.headers.setdefault(\"content-disposition\", content_disposition)\n        self.stat_result = stat_result\n        if stat_result is not None:\n            self.set_stat_headers(stat_result)\n\n    @classmethod\n    def get_stat_headers(cls, stat_result: os.stat_result) -> typing.Dict[str, str]:\n        content_length = str(stat_result.st_size)\n        last_modified = formatdate(stat_result.st_mtime, usegmt=True)\n        etag_base = str(stat_result.st_mtime) + \"-\" + str(stat_result.st_size)\n        etag = hashlib.md5(etag_base.encode()).hexdigest()\n        return {\n            \"content-length\": content_length,\n            \"last-modified\": last_modified,\n            \"etag\": etag,\n        }\n\n    def set_stat_headers(self, stat_result: os.stat_result) -> None:\n        stat_headers = self.get_stat_headers(stat_result)\n        for name, value in stat_headers.items():\n            self.headers.setdefault(name, value)\n\n    async def __call__(self, receive: Receive, send: Send) -> None:\n        if self.stat_result is None:\n            try:\n                stat_result = await aio_stat(self.path)\n                self.set_stat_headers(stat_result)\n            except FileNotFoundError:\n                raise RuntimeError(f\"File at path {self.path} does not exist.\")\n            else:\n                mode = stat_result.st_mode\n                if not stat.S_ISREG(mode):\n                    raise RuntimeError(f\"File at path {self.path} is not a file.\")\n        await send(\n            {\n                \"type\": \"http.response.start\",\n                \"status\": self.status_code,\n                \"headers\": self.raw_headers,\n            }\n        )\n        if self.send_header_only:\n            await send({\"type\": \"http.response.body\"})\n        else:\n            async with aiofiles.open(self.path, mode=\"rb\") as file:\n                more_body = True\n                while more_body:\n                    chunk = await file.read(self.chunk_size)\n                    more_body = len(chunk) == self.chunk_size\n                    await send(\n                        {\n                            \"type\": \"http.response.body\",\n                            \"body\": chunk,\n                            \"more_body\": more_body,\n                        }\n                    )\n        if self.background is not None:\n            await self.background()\n", "path": "starlette/responses.py"}]}