We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
AsnycIteratorStream should error if `__iter__` called twice.
For defensive programming, the `AsyncIteratorStream` implementation should track `.stream_consumed` in `__iter__`, and raise a `RuntimeError` if it is called twice.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `httpx/content_streams.py`
Content:
```
1 import binascii
2 import mimetypes
3 import os
4 import typing
5 from io import BytesIO
6 from json import dumps as json_dumps
7 from pathlib import Path
8 from urllib.parse import urlencode
9 
10 from .utils import format_form_param
11 
12 RequestData = typing.Union[dict, str, bytes, typing.AsyncIterator[bytes]]
13 
14 RequestFiles = typing.Dict[
15     str,
16     typing.Union[
17         # file (or str)
18         typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],
19         # (filename, file (or str))
20         typing.Tuple[
21             typing.Optional[str], typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],
22         ],
23         # (filename, file (or str), content_type)
24         typing.Tuple[
25             typing.Optional[str],
26             typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],
27             typing.Optional[str],
28         ],
29     ],
30 ]
31 
32 
33 class ContentStream:
34     def get_headers(self) -> typing.Dict[str, str]:
35         """
36         Return a dictionary of headers that are implied by the encoding.
37         """
38         return {}
39 
40     def can_replay(self) -> bool:
41         """
42         Return `True` if `__aiter__` can be called multiple times.
43 
44         We need this in cases such determining if we can re-issue a request
45         body when we receive a redirect response.
46         """
47         return True
48 
49     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
50         yield b""
51 
52     async def aclose(self) -> None:
53         pass
54 
55 
56 class ByteStream(ContentStream):
57     """
58     Request content encoded as plain bytes.
59     """
60 
61     def __init__(self, body: typing.Union[str, bytes]) -> None:
62         self.body = body.encode("utf-8") if isinstance(body, str) else body
63 
64     def get_headers(self) -> typing.Dict[str, str]:
65         if not self.body:
66             return {}
67         content_length = str(len(self.body))
68         return {"Content-Length": content_length}
69 
70     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
71         yield self.body
72 
73 
74 class AsyncIteratorStream(ContentStream):
75     """
76     Request content encoded as plain bytes, using an async byte iterator.
77     """
78 
79     def __init__(
80         self, aiterator: typing.AsyncIterator[bytes], close_func: typing.Callable = None
81     ) -> None:
82         self.aiterator = aiterator
83         self.close_func = close_func
84 
85     def can_replay(self) -> bool:
86         return False
87 
88     def get_headers(self) -> typing.Dict[str, str]:
89         return {"Transfer-Encoding": "chunked"}
90 
91     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
92         async for part in self.aiterator:
93             yield part
94 
95     async def aclose(self) -> None:
96         if self.close_func is not None:
97             await self.close_func()
98 
99 
100 class JSONStream(ContentStream):
101     """
102     Request content encoded as JSON.
103     """
104 
105     def __init__(self, json: typing.Any) -> None:
106         self.body = json_dumps(json).encode("utf-8")
107 
108     def get_headers(self) -> typing.Dict[str, str]:
109         content_length = str(len(self.body))
110         content_type = "application/json"
111         return {"Content-Length": content_length, "Content-Type": content_type}
112 
113     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
114         yield self.body
115 
116 
117 class URLEncodedStream(ContentStream):
118     """
119     Request content as URL encoded form data.
120     """
121 
122     def __init__(self, data: dict) -> None:
123         self.body = urlencode(data, doseq=True).encode("utf-8")
124 
125     def get_headers(self) -> typing.Dict[str, str]:
126         content_length = str(len(self.body))
127         content_type = "application/x-www-form-urlencoded"
128         return {"Content-Length": content_length, "Content-Type": content_type}
129 
130     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
131         yield self.body
132 
133 
134 class MultipartStream(ContentStream):
135     """
136     Request content as multipart encoded form data.
137     """
138 
139     class DataField:
140         """
141         A single form field item, within a multipart form field.
142         """
143 
144         def __init__(self, name: str, value: typing.Union[str, bytes]) -> None:
145             if not isinstance(name, str):
146                 raise TypeError("Invalid type for name. Expected str.")
147             if not isinstance(value, (str, bytes)):
148                 raise TypeError("Invalid type for value. Expected str or bytes.")
149             self.name = name
150             self.value = value
151 
152         def render_headers(self) -> bytes:
153             name = format_form_param("name", self.name)
154             return b"".join([b"Content-Disposition: form-data; ", name, b"\r\n\r\n"])
155 
156         def render_data(self) -> bytes:
157             return (
158                 self.value
159                 if isinstance(self.value, bytes)
160                 else self.value.encode("utf-8")
161             )
162 
163     class FileField:
164         """
165         A single file field item, within a multipart form field.
166         """
167 
168         def __init__(
169             self, name: str, value: typing.Union[typing.IO[typing.AnyStr], tuple]
170         ) -> None:
171             self.name = name
172             if not isinstance(value, tuple):
173                 self.filename = Path(str(getattr(value, "name", "upload"))).name
174                 self.file = (
175                     value
176                 )  # type: typing.Union[typing.IO[str], typing.IO[bytes]]
177                 self.content_type = self.guess_content_type()
178             else:
179                 self.filename = value[0]
180                 self.file = value[1]
181                 self.content_type = (
182                     value[2] if len(value) > 2 else self.guess_content_type()
183                 )
184 
185         def guess_content_type(self) -> typing.Optional[str]:
186             if self.filename:
187                 return (
188                     mimetypes.guess_type(self.filename)[0] or "application/octet-stream"
189                 )
190             else:
191                 return None
192 
193         def render_headers(self) -> bytes:
194             parts = [
195                 b"Content-Disposition: form-data; ",
196                 format_form_param("name", self.name),
197             ]
198             if self.filename:
199                 filename = format_form_param("filename", self.filename)
200                 parts.extend([b"; ", filename])
201             if self.content_type is not None:
202                 content_type = self.content_type.encode()
203                 parts.extend([b"\r\nContent-Type: ", content_type])
204             parts.append(b"\r\n\r\n")
205             return b"".join(parts)
206 
207         def render_data(self) -> bytes:
208             if isinstance(self.file, str):
209                 content = self.file
210             else:
211                 content = self.file.read()
212             return content.encode("utf-8") if isinstance(content, str) else content
213 
214     def __init__(self, data: dict, files: dict, boundary: bytes = None) -> None:
215         body = BytesIO()
216         if boundary is None:
217             boundary = binascii.hexlify(os.urandom(16))
218 
219         for field in self.iter_fields(data, files):
220             body.write(b"--%s\r\n" % boundary)
221             body.write(field.render_headers())
222             body.write(field.render_data())
223             body.write(b"\r\n")
224 
225         body.write(b"--%s--\r\n" % boundary)
226 
227         self.content_type = "multipart/form-data; boundary=%s" % boundary.decode(
228             "ascii"
229         )
230         self.body = body.getvalue()
231 
232     def iter_fields(
233         self, data: dict, files: dict
234     ) -> typing.Iterator[typing.Union["FileField", "DataField"]]:
235         for name, value in data.items():
236             if isinstance(value, (list, dict)):
237                 for item in value:
238                     yield self.DataField(name=name, value=item)
239             else:
240                 yield self.DataField(name=name, value=value)
241 
242         for name, value in files.items():
243             yield self.FileField(name=name, value=value)
244 
245     def get_headers(self) -> typing.Dict[str, str]:
246         content_length = str(len(self.body))
247         content_type = self.content_type
248         return {"Content-Length": content_length, "Content-Type": content_type}
249 
250     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
251         yield self.body
252 
253 
254 def encode(
255     data: RequestData = None,
256     files: RequestFiles = None,
257     json: typing.Any = None,
258     boundary: bytes = None,
259 ) -> ContentStream:
260     """
261     Handles encoding the given `data`, `files`, and `json`, returning
262     a `ContentStream` implementation.
263     """
264     if data is None:
265         if json is not None:
266             return JSONStream(json=json)
267         elif files:
268             return MultipartStream(data={}, files=files, boundary=boundary)
269         else:
270             return ByteStream(body=b"")
271     elif isinstance(data, dict):
272         if files is not None:
273             return MultipartStream(data=data, files=files, boundary=boundary)
274         else:
275             return URLEncodedStream(data=data)
276     elif isinstance(data, (str, bytes)):
277         return ByteStream(body=data)
278     else:
279         return AsyncIteratorStream(aiterator=data)
280
```
--- 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/httpx/content_streams.py b/httpx/content_streams.py
--- a/httpx/content_streams.py
+++ b/httpx/content_streams.py
@@ -7,6 +7,7 @@
 from pathlib import Path
 from urllib.parse import urlencode
 
+from .exceptions import StreamConsumed
 from .utils import format_form_param
 
 RequestData = typing.Union[dict, str, bytes, typing.AsyncIterator[bytes]]
@@ -81,6 +82,7 @@
     ) -> None:
         self.aiterator = aiterator
         self.close_func = close_func
+        self.is_stream_consumed = False
 
     def can_replay(self) -> bool:
         return False
@@ -89,6 +91,9 @@
         return {"Transfer-Encoding": "chunked"}
 
     async def __aiter__(self) -> typing.AsyncIterator[bytes]:
+        if self.is_stream_consumed:
+            raise StreamConsumed()
+        self.is_stream_consumed = True
         async for part in self.aiterator:
             yield part

{"golden_diff": "diff --git a/httpx/content_streams.py b/httpx/content_streams.py\n--- a/httpx/content_streams.py\n+++ b/httpx/content_streams.py\n@@ -7,6 +7,7 @@\n from pathlib import Path\n from urllib.parse import urlencode\n \n+from .exceptions import StreamConsumed\n from .utils import format_form_param\n \n RequestData = typing.Union[dict, str, bytes, typing.AsyncIterator[bytes]]\n@@ -81,6 +82,7 @@\n     ) -> None:\n         self.aiterator = aiterator\n         self.close_func = close_func\n+        self.is_stream_consumed = False\n \n     def can_replay(self) -> bool:\n         return False\n@@ -89,6 +91,9 @@\n         return {\"Transfer-Encoding\": \"chunked\"}\n \n     async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n+        if self.is_stream_consumed:\n+            raise StreamConsumed()\n+        self.is_stream_consumed = True\n         async for part in self.aiterator:\n             yield part\n", "issue": "AsnycIteratorStream should error if `__iter__` called twice.\nFor defensive programming, the `AsyncIteratorStream` implementation should track `.stream_consumed` in `__iter__`, and raise a `RuntimeError` if it is called twice.\n", "before_files": [{"content": "import binascii\nimport mimetypes\nimport os\nimport typing\nfrom io import BytesIO\nfrom json import dumps as json_dumps\nfrom pathlib import Path\nfrom urllib.parse import urlencode\n\nfrom .utils import format_form_param\n\nRequestData = typing.Union[dict, str, bytes, typing.AsyncIterator[bytes]]\n\nRequestFiles = typing.Dict[\n    str,\n    typing.Union[\n        # file (or str)\n        typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],\n        # (filename, file (or str))\n        typing.Tuple[\n            typing.Optional[str], typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],\n        ],\n        # (filename, file (or str), content_type)\n        typing.Tuple[\n            typing.Optional[str],\n            typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],\n            typing.Optional[str],\n        ],\n    ],\n]\n\n\nclass ContentStream:\n    def get_headers(self) -> typing.Dict[str, str]:\n        \"\"\"\n        Return a dictionary of headers that are implied by the encoding.\n        \"\"\"\n        return {}\n\n    def can_replay(self) -> bool:\n        \"\"\"\n        Return `True` if `__aiter__` can be called multiple times.\n\n        We need this in cases such determining if we can re-issue a request\n        body when we receive a redirect response.\n        \"\"\"\n        return True\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield b\"\"\n\n    async def aclose(self) -> None:\n        pass\n\n\nclass ByteStream(ContentStream):\n    \"\"\"\n    Request content encoded as plain bytes.\n    \"\"\"\n\n    def __init__(self, body: typing.Union[str, bytes]) -> None:\n        self.body = body.encode(\"utf-8\") if isinstance(body, str) else body\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        if not self.body:\n            return {}\n        content_length = str(len(self.body))\n        return {\"Content-Length\": content_length}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\nclass AsyncIteratorStream(ContentStream):\n    \"\"\"\n    Request content encoded as plain bytes, using an async byte iterator.\n    \"\"\"\n\n    def __init__(\n        self, aiterator: typing.AsyncIterator[bytes], close_func: typing.Callable = None\n    ) -> None:\n        self.aiterator = aiterator\n        self.close_func = close_func\n\n    def can_replay(self) -> bool:\n        return False\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        return {\"Transfer-Encoding\": \"chunked\"}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        async for part in self.aiterator:\n            yield part\n\n    async def aclose(self) -> None:\n        if self.close_func is not None:\n            await self.close_func()\n\n\nclass JSONStream(ContentStream):\n    \"\"\"\n    Request content encoded as JSON.\n    \"\"\"\n\n    def __init__(self, json: typing.Any) -> None:\n        self.body = json_dumps(json).encode(\"utf-8\")\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        content_length = str(len(self.body))\n        content_type = \"application/json\"\n        return {\"Content-Length\": content_length, \"Content-Type\": content_type}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\nclass URLEncodedStream(ContentStream):\n    \"\"\"\n    Request content as URL encoded form data.\n    \"\"\"\n\n    def __init__(self, data: dict) -> None:\n        self.body = urlencode(data, doseq=True).encode(\"utf-8\")\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        content_length = str(len(self.body))\n        content_type = \"application/x-www-form-urlencoded\"\n        return {\"Content-Length\": content_length, \"Content-Type\": content_type}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\nclass MultipartStream(ContentStream):\n    \"\"\"\n    Request content as multipart encoded form data.\n    \"\"\"\n\n    class DataField:\n        \"\"\"\n        A single form field item, within a multipart form field.\n        \"\"\"\n\n        def __init__(self, name: str, value: typing.Union[str, bytes]) -> None:\n            if not isinstance(name, str):\n                raise TypeError(\"Invalid type for name. Expected str.\")\n            if not isinstance(value, (str, bytes)):\n                raise TypeError(\"Invalid type for value. Expected str or bytes.\")\n            self.name = name\n            self.value = value\n\n        def render_headers(self) -> bytes:\n            name = format_form_param(\"name\", self.name)\n            return b\"\".join([b\"Content-Disposition: form-data; \", name, b\"\\r\\n\\r\\n\"])\n\n        def render_data(self) -> bytes:\n            return (\n                self.value\n                if isinstance(self.value, bytes)\n                else self.value.encode(\"utf-8\")\n            )\n\n    class FileField:\n        \"\"\"\n        A single file field item, within a multipart form field.\n        \"\"\"\n\n        def __init__(\n            self, name: str, value: typing.Union[typing.IO[typing.AnyStr], tuple]\n        ) -> None:\n            self.name = name\n            if not isinstance(value, tuple):\n                self.filename = Path(str(getattr(value, \"name\", \"upload\"))).name\n                self.file = (\n                    value\n                )  # type: typing.Union[typing.IO[str], typing.IO[bytes]]\n                self.content_type = self.guess_content_type()\n            else:\n                self.filename = value[0]\n                self.file = value[1]\n                self.content_type = (\n                    value[2] if len(value) > 2 else self.guess_content_type()\n                )\n\n        def guess_content_type(self) -> typing.Optional[str]:\n            if self.filename:\n                return (\n                    mimetypes.guess_type(self.filename)[0] or \"application/octet-stream\"\n                )\n            else:\n                return None\n\n        def render_headers(self) -> bytes:\n            parts = [\n                b\"Content-Disposition: form-data; \",\n                format_form_param(\"name\", self.name),\n            ]\n            if self.filename:\n                filename = format_form_param(\"filename\", self.filename)\n                parts.extend([b\"; \", filename])\n            if self.content_type is not None:\n                content_type = self.content_type.encode()\n                parts.extend([b\"\\r\\nContent-Type: \", content_type])\n            parts.append(b\"\\r\\n\\r\\n\")\n            return b\"\".join(parts)\n\n        def render_data(self) -> bytes:\n            if isinstance(self.file, str):\n                content = self.file\n            else:\n                content = self.file.read()\n            return content.encode(\"utf-8\") if isinstance(content, str) else content\n\n    def __init__(self, data: dict, files: dict, boundary: bytes = None) -> None:\n        body = BytesIO()\n        if boundary is None:\n            boundary = binascii.hexlify(os.urandom(16))\n\n        for field in self.iter_fields(data, files):\n            body.write(b\"--%s\\r\\n\" % boundary)\n            body.write(field.render_headers())\n            body.write(field.render_data())\n            body.write(b\"\\r\\n\")\n\n        body.write(b\"--%s--\\r\\n\" % boundary)\n\n        self.content_type = \"multipart/form-data; boundary=%s\" % boundary.decode(\n            \"ascii\"\n        )\n        self.body = body.getvalue()\n\n    def iter_fields(\n        self, data: dict, files: dict\n    ) -> typing.Iterator[typing.Union[\"FileField\", \"DataField\"]]:\n        for name, value in data.items():\n            if isinstance(value, (list, dict)):\n                for item in value:\n                    yield self.DataField(name=name, value=item)\n            else:\n                yield self.DataField(name=name, value=value)\n\n        for name, value in files.items():\n            yield self.FileField(name=name, value=value)\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        content_length = str(len(self.body))\n        content_type = self.content_type\n        return {\"Content-Length\": content_length, \"Content-Type\": content_type}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\ndef encode(\n    data: RequestData = None,\n    files: RequestFiles = None,\n    json: typing.Any = None,\n    boundary: bytes = None,\n) -> ContentStream:\n    \"\"\"\n    Handles encoding the given `data`, `files`, and `json`, returning\n    a `ContentStream` implementation.\n    \"\"\"\n    if data is None:\n        if json is not None:\n            return JSONStream(json=json)\n        elif files:\n            return MultipartStream(data={}, files=files, boundary=boundary)\n        else:\n            return ByteStream(body=b\"\")\n    elif isinstance(data, dict):\n        if files is not None:\n            return MultipartStream(data=data, files=files, boundary=boundary)\n        else:\n            return URLEncodedStream(data=data)\n    elif isinstance(data, (str, bytes)):\n        return ByteStream(body=data)\n    else:\n        return AsyncIteratorStream(aiterator=data)\n", "path": "httpx/content_streams.py"}], "after_files": [{"content": "import binascii\nimport mimetypes\nimport os\nimport typing\nfrom io import BytesIO\nfrom json import dumps as json_dumps\nfrom pathlib import Path\nfrom urllib.parse import urlencode\n\nfrom .exceptions import StreamConsumed\nfrom .utils import format_form_param\n\nRequestData = typing.Union[dict, str, bytes, typing.AsyncIterator[bytes]]\n\nRequestFiles = typing.Dict[\n    str,\n    typing.Union[\n        # file (or str)\n        typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],\n        # (filename, file (or str))\n        typing.Tuple[\n            typing.Optional[str], typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],\n        ],\n        # (filename, file (or str), content_type)\n        typing.Tuple[\n            typing.Optional[str],\n            typing.Union[typing.IO[typing.AnyStr], typing.AnyStr],\n            typing.Optional[str],\n        ],\n    ],\n]\n\n\nclass ContentStream:\n    def get_headers(self) -> typing.Dict[str, str]:\n        \"\"\"\n        Return a dictionary of headers that are implied by the encoding.\n        \"\"\"\n        return {}\n\n    def can_replay(self) -> bool:\n        \"\"\"\n        Return `True` if `__aiter__` can be called multiple times.\n\n        We need this in cases such determining if we can re-issue a request\n        body when we receive a redirect response.\n        \"\"\"\n        return True\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield b\"\"\n\n    async def aclose(self) -> None:\n        pass\n\n\nclass ByteStream(ContentStream):\n    \"\"\"\n    Request content encoded as plain bytes.\n    \"\"\"\n\n    def __init__(self, body: typing.Union[str, bytes]) -> None:\n        self.body = body.encode(\"utf-8\") if isinstance(body, str) else body\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        if not self.body:\n            return {}\n        content_length = str(len(self.body))\n        return {\"Content-Length\": content_length}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\nclass AsyncIteratorStream(ContentStream):\n    \"\"\"\n    Request content encoded as plain bytes, using an async byte iterator.\n    \"\"\"\n\n    def __init__(\n        self, aiterator: typing.AsyncIterator[bytes], close_func: typing.Callable = None\n    ) -> None:\n        self.aiterator = aiterator\n        self.close_func = close_func\n        self.is_stream_consumed = False\n\n    def can_replay(self) -> bool:\n        return False\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        return {\"Transfer-Encoding\": \"chunked\"}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        if self.is_stream_consumed:\n            raise StreamConsumed()\n        self.is_stream_consumed = True\n        async for part in self.aiterator:\n            yield part\n\n    async def aclose(self) -> None:\n        if self.close_func is not None:\n            await self.close_func()\n\n\nclass JSONStream(ContentStream):\n    \"\"\"\n    Request content encoded as JSON.\n    \"\"\"\n\n    def __init__(self, json: typing.Any) -> None:\n        self.body = json_dumps(json).encode(\"utf-8\")\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        content_length = str(len(self.body))\n        content_type = \"application/json\"\n        return {\"Content-Length\": content_length, \"Content-Type\": content_type}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\nclass URLEncodedStream(ContentStream):\n    \"\"\"\n    Request content as URL encoded form data.\n    \"\"\"\n\n    def __init__(self, data: dict) -> None:\n        self.body = urlencode(data, doseq=True).encode(\"utf-8\")\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        content_length = str(len(self.body))\n        content_type = \"application/x-www-form-urlencoded\"\n        return {\"Content-Length\": content_length, \"Content-Type\": content_type}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\nclass MultipartStream(ContentStream):\n    \"\"\"\n    Request content as multipart encoded form data.\n    \"\"\"\n\n    class DataField:\n        \"\"\"\n        A single form field item, within a multipart form field.\n        \"\"\"\n\n        def __init__(self, name: str, value: typing.Union[str, bytes]) -> None:\n            if not isinstance(name, str):\n                raise TypeError(\"Invalid type for name. Expected str.\")\n            if not isinstance(value, (str, bytes)):\n                raise TypeError(\"Invalid type for value. Expected str or bytes.\")\n            self.name = name\n            self.value = value\n\n        def render_headers(self) -> bytes:\n            name = format_form_param(\"name\", self.name)\n            return b\"\".join([b\"Content-Disposition: form-data; \", name, b\"\\r\\n\\r\\n\"])\n\n        def render_data(self) -> bytes:\n            return (\n                self.value\n                if isinstance(self.value, bytes)\n                else self.value.encode(\"utf-8\")\n            )\n\n    class FileField:\n        \"\"\"\n        A single file field item, within a multipart form field.\n        \"\"\"\n\n        def __init__(\n            self, name: str, value: typing.Union[typing.IO[typing.AnyStr], tuple]\n        ) -> None:\n            self.name = name\n            if not isinstance(value, tuple):\n                self.filename = Path(str(getattr(value, \"name\", \"upload\"))).name\n                self.file = (\n                    value\n                )  # type: typing.Union[typing.IO[str], typing.IO[bytes]]\n                self.content_type = self.guess_content_type()\n            else:\n                self.filename = value[0]\n                self.file = value[1]\n                self.content_type = (\n                    value[2] if len(value) > 2 else self.guess_content_type()\n                )\n\n        def guess_content_type(self) -> typing.Optional[str]:\n            if self.filename:\n                return (\n                    mimetypes.guess_type(self.filename)[0] or \"application/octet-stream\"\n                )\n            else:\n                return None\n\n        def render_headers(self) -> bytes:\n            parts = [\n                b\"Content-Disposition: form-data; \",\n                format_form_param(\"name\", self.name),\n            ]\n            if self.filename:\n                filename = format_form_param(\"filename\", self.filename)\n                parts.extend([b\"; \", filename])\n            if self.content_type is not None:\n                content_type = self.content_type.encode()\n                parts.extend([b\"\\r\\nContent-Type: \", content_type])\n            parts.append(b\"\\r\\n\\r\\n\")\n            return b\"\".join(parts)\n\n        def render_data(self) -> bytes:\n            if isinstance(self.file, str):\n                content = self.file\n            else:\n                content = self.file.read()\n            return content.encode(\"utf-8\") if isinstance(content, str) else content\n\n    def __init__(self, data: dict, files: dict, boundary: bytes = None) -> None:\n        body = BytesIO()\n        if boundary is None:\n            boundary = binascii.hexlify(os.urandom(16))\n\n        for field in self.iter_fields(data, files):\n            body.write(b\"--%s\\r\\n\" % boundary)\n            body.write(field.render_headers())\n            body.write(field.render_data())\n            body.write(b\"\\r\\n\")\n\n        body.write(b\"--%s--\\r\\n\" % boundary)\n\n        self.content_type = \"multipart/form-data; boundary=%s\" % boundary.decode(\n            \"ascii\"\n        )\n        self.body = body.getvalue()\n\n    def iter_fields(\n        self, data: dict, files: dict\n    ) -> typing.Iterator[typing.Union[\"FileField\", \"DataField\"]]:\n        for name, value in data.items():\n            if isinstance(value, (list, dict)):\n                for item in value:\n                    yield self.DataField(name=name, value=item)\n            else:\n                yield self.DataField(name=name, value=value)\n\n        for name, value in files.items():\n            yield self.FileField(name=name, value=value)\n\n    def get_headers(self) -> typing.Dict[str, str]:\n        content_length = str(len(self.body))\n        content_type = self.content_type\n        return {\"Content-Length\": content_length, \"Content-Type\": content_type}\n\n    async def __aiter__(self) -> typing.AsyncIterator[bytes]:\n        yield self.body\n\n\ndef encode(\n    data: RequestData = None,\n    files: RequestFiles = None,\n    json: typing.Any = None,\n    boundary: bytes = None,\n) -> ContentStream:\n    \"\"\"\n    Handles encoding the given `data`, `files`, and `json`, returning\n    a `ContentStream` implementation.\n    \"\"\"\n    if data is None:\n        if json is not None:\n            return JSONStream(json=json)\n        elif files:\n            return MultipartStream(data={}, files=files, boundary=boundary)\n        else:\n            return ByteStream(body=b\"\")\n    elif isinstance(data, dict):\n        if files is not None:\n            return MultipartStream(data=data, files=files, boundary=boundary)\n        else:\n            return URLEncodedStream(data=data)\n    elif isinstance(data, (str, bytes)):\n        return ByteStream(body=data)\n    else:\n        return AsyncIteratorStream(aiterator=data)\n", "path": "httpx/content_streams.py"}]}