We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
aiter_lines() doesn't return full lines that span multiple chunks
<https://gist.github.com/scr-oath/aa76d200222a0409d09a0d6feb1a13e2> shows an example setup using cherry.py as server that just outputs two lines - the json is big enough to be sent in two chunks; httpx aiter_lines() gets confused and sends data from the middle of the json line - seems to skip the starting part - which was most likely sent in a chunk without a newline

### test-httpx.py
```python
import asyncio
import json

import httpx


class TestHttpx:
    def __init__(self):
        pass

    async def __call__(self):
        http_client = httpx.AsyncClient()
        async with http_client.stream(method="GET", url='http://localhost:8080/lines') as response:
            is_message = True
            async for line in response.aiter_lines():
                is_message = not is_message
                if is_message:
                    message = json.loads(line)
                    print(message)


def main():
    test_httpx = TestHttpx()
    asyncio.run(test_httpx())


if __name__ == '__main__':
    main()
```

--- 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/_decoders.py`
Content:
```
1 """
2 Handlers for Content-Encoding.
3 
4 See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
5 """
6 import codecs
7 import typing
8 import zlib
9 
10 import chardet
11 
12 from ._exceptions import DecodingError
13 
14 try:
15     import brotli
16 except ImportError:  # pragma: nocover
17     brotli = None
18 
19 
20 class Decoder:
21     def decode(self, data: bytes) -> bytes:
22         raise NotImplementedError()  # pragma: nocover
23 
24     def flush(self) -> bytes:
25         raise NotImplementedError()  # pragma: nocover
26 
27 
28 class IdentityDecoder(Decoder):
29     """
30     Handle unencoded data.
31     """
32 
33     def decode(self, data: bytes) -> bytes:
34         return data
35 
36     def flush(self) -> bytes:
37         return b""
38 
39 
40 class DeflateDecoder(Decoder):
41     """
42     Handle 'deflate' decoding.
43 
44     See: https://stackoverflow.com/questions/1838699
45     """
46 
47     def __init__(self) -> None:
48         self.first_attempt = True
49         self.decompressor = zlib.decompressobj()
50 
51     def decode(self, data: bytes) -> bytes:
52         was_first_attempt = self.first_attempt
53         self.first_attempt = False
54         try:
55             return self.decompressor.decompress(data)
56         except zlib.error as exc:
57             if was_first_attempt:
58                 self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
59                 return self.decode(data)
60             raise DecodingError from exc
61 
62     def flush(self) -> bytes:
63         try:
64             return self.decompressor.flush()
65         except zlib.error as exc:  # pragma: nocover
66             raise DecodingError from exc
67 
68 
69 class GZipDecoder(Decoder):
70     """
71     Handle 'gzip' decoding.
72 
73     See: https://stackoverflow.com/questions/1838699
74     """
75 
76     def __init__(self) -> None:
77         self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16)
78 
79     def decode(self, data: bytes) -> bytes:
80         try:
81             return self.decompressor.decompress(data)
82         except zlib.error as exc:
83             raise DecodingError from exc
84 
85     def flush(self) -> bytes:
86         try:
87             return self.decompressor.flush()
88         except zlib.error as exc:  # pragma: nocover
89             raise DecodingError from exc
90 
91 
92 class BrotliDecoder(Decoder):
93     """
94     Handle 'brotli' decoding.
95 
96     Requires `pip install brotlipy`. See: https://brotlipy.readthedocs.io/
97         or   `pip install brotli`. See https://github.com/google/brotli
98     Supports both 'brotlipy' and 'Brotli' packages since they share an import
99     name. The top branches are for 'brotlipy' and bottom branches for 'Brotli'
100     """
101 
102     def __init__(self) -> None:
103         assert (
104             brotli is not None
105         ), "The 'brotlipy' or 'brotli' library must be installed to use 'BrotliDecoder'"
106         self.decompressor = brotli.Decompressor()
107         self.seen_data = False
108         if hasattr(self.decompressor, "decompress"):
109             self._decompress = self.decompressor.decompress
110         else:
111             self._decompress = self.decompressor.process  # pragma: nocover
112 
113     def decode(self, data: bytes) -> bytes:
114         if not data:
115             return b""
116         self.seen_data = True
117         try:
118             return self._decompress(data)
119         except brotli.error as exc:
120             raise DecodingError from exc
121 
122     def flush(self) -> bytes:
123         if not self.seen_data:
124             return b""
125         try:
126             if hasattr(self.decompressor, "finish"):
127                 self.decompressor.finish()
128             return b""
129         except brotli.error as exc:  # pragma: nocover
130             raise DecodingError from exc
131 
132 
133 class MultiDecoder(Decoder):
134     """
135     Handle the case where multiple encodings have been applied.
136     """
137 
138     def __init__(self, children: typing.Sequence[Decoder]) -> None:
139         """
140         'children' should be a sequence of decoders in the order in which
141         each was applied.
142         """
143         # Note that we reverse the order for decoding.
144         self.children = list(reversed(children))
145 
146     def decode(self, data: bytes) -> bytes:
147         for child in self.children:
148             data = child.decode(data)
149         return data
150 
151     def flush(self) -> bytes:
152         data = b""
153         for child in self.children:
154             data = child.decode(data) + child.flush()
155         return data
156 
157 
158 class TextDecoder:
159     """
160     Handles incrementally decoding bytes into text
161     """
162 
163     def __init__(self, encoding: typing.Optional[str] = None):
164         self.decoder: typing.Optional[codecs.IncrementalDecoder] = (
165             None if encoding is None else codecs.getincrementaldecoder(encoding)()
166         )
167         self.detector = chardet.universaldetector.UniversalDetector()
168 
169         # This buffer is only needed if 'decoder' is 'None'
170         # we want to trigger errors if data is getting added to
171         # our internal buffer for some silly reason while
172         # a decoder is discovered.
173         self.buffer: typing.Optional[bytearray] = None if self.decoder else bytearray()
174 
175     def decode(self, data: bytes) -> str:
176         try:
177             if self.decoder is not None:
178                 text = self.decoder.decode(data)
179             else:
180                 assert self.buffer is not None
181                 text = ""
182                 self.detector.feed(data)
183                 self.buffer += data
184 
185                 # Should be more than enough data to process, we don't
186                 # want to buffer too long as chardet will wait until
187                 # detector.close() is used to give back common
188                 # encodings like 'utf-8'.
189                 if len(self.buffer) >= 4096:
190                     self.decoder = codecs.getincrementaldecoder(
191                         self._detector_result()
192                     )()
193                     text = self.decoder.decode(bytes(self.buffer), False)
194                     self.buffer = None
195 
196             return text
197         except UnicodeDecodeError:  # pragma: nocover
198             raise DecodingError() from None
199 
200     def flush(self) -> str:
201         try:
202             if self.decoder is None:
203                 # Empty string case as chardet is guaranteed to not have a guess.
204                 assert self.buffer is not None
205                 if len(self.buffer) == 0:
206                     return ""
207                 return bytes(self.buffer).decode(self._detector_result())
208 
209             return self.decoder.decode(b"", True)
210         except UnicodeDecodeError:  # pragma: nocover
211             raise DecodingError() from None
212 
213     def _detector_result(self) -> str:
214         self.detector.close()
215         result = self.detector.result["encoding"]
216         if not result:  # pragma: nocover
217             raise DecodingError("Unable to determine encoding of content")
218 
219         return result
220 
221 
222 class LineDecoder:
223     """
224     Handles incrementally reading lines from text.
225 
226     Uses universal line decoding, supporting any of `\n`, `\r`, or `\r\n`
227     as line endings, normalizing to `\n`.
228     """
229 
230     def __init__(self) -> None:
231         self.buffer = ""
232 
233     def decode(self, text: str) -> typing.List[str]:
234         lines = []
235 
236         if text.startswith("\n") and self.buffer and self.buffer[-1] == "\r":
237             # Handle the case where we have an "\r\n" split across
238             # our previous input, and our new chunk.
239             lines.append(self.buffer[:-1] + "\n")
240             self.buffer = ""
241             text = text[1:]
242 
243         while text:
244             num_chars = len(text)
245             for idx in range(num_chars):
246                 char = text[idx]
247                 next_char = None if idx + 1 == num_chars else text[idx + 1]
248                 if char == "\n":
249                     lines.append(self.buffer + text[: idx + 1])
250                     self.buffer = ""
251                     text = text[idx + 1 :]
252                     break
253                 elif char == "\r" and next_char == "\n":
254                     lines.append(self.buffer + text[:idx] + "\n")
255                     self.buffer = ""
256                     text = text[idx + 2 :]
257                     break
258                 elif char == "\r" and next_char is not None:
259                     lines.append(self.buffer + text[:idx] + "\n")
260                     self.buffer = ""
261                     text = text[idx + 1 :]
262                     break
263                 elif next_char is None:
264                     self.buffer = text
265                     text = ""
266                     break
267 
268         return lines
269 
270     def flush(self) -> typing.List[str]:
271         if self.buffer.endswith("\r"):
272             # Handle the case where we had a trailing '\r', which could have
273             # been a '\r\n' pair.
274             lines = [self.buffer[:-1] + "\n"]
275         elif self.buffer:
276             lines = [self.buffer]
277         else:
278             lines = []
279         self.buffer = ""
280         return lines
281 
282 
283 SUPPORTED_DECODERS = {
284     "identity": IdentityDecoder,
285     "gzip": GZipDecoder,
286     "deflate": DeflateDecoder,
287     "br": BrotliDecoder,
288 }
289 
290 
291 if brotli is None:
292     SUPPORTED_DECODERS.pop("br")  # pragma: nocover
293
```
--- 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/_decoders.py b/httpx/_decoders.py
--- a/httpx/_decoders.py
+++ b/httpx/_decoders.py
@@ -261,7 +261,7 @@
                     text = text[idx + 1 :]
                     break
                 elif next_char is None:
-                    self.buffer = text
+                    self.buffer += text
                     text = ""
                     break

{"golden_diff": "diff --git a/httpx/_decoders.py b/httpx/_decoders.py\n--- a/httpx/_decoders.py\n+++ b/httpx/_decoders.py\n@@ -261,7 +261,7 @@\n                     text = text[idx + 1 :]\n                     break\n                 elif next_char is None:\n-                    self.buffer = text\n+                    self.buffer += text\n                     text = \"\"\n                     break\n", "issue": "aiter_lines() doesn't return full lines that span multiple chunks\n<https://gist.github.com/scr-oath/aa76d200222a0409d09a0d6feb1a13e2> shows an example setup using cherry.py as server that just outputs two lines - the json is big enough to be sent in two chunks; httpx aiter_lines() gets confused and sends data from the middle of the json line - seems to skip the starting part - which was most likely sent in a chunk without a newline\r\n\r\n### test-httpx.py\r\n```python\r\nimport asyncio\r\nimport json\r\n\r\nimport httpx\r\n\r\n\r\nclass TestHttpx:\r\n    def __init__(self):\r\n        pass\r\n\r\n    async def __call__(self):\r\n        http_client = httpx.AsyncClient()\r\n        async with http_client.stream(method=\"GET\", url='http://localhost:8080/lines') as response:\r\n            is_message = True\r\n            async for line in response.aiter_lines():\r\n                is_message = not is_message\r\n                if is_message:\r\n                    message = json.loads(line)\r\n                    print(message)\r\n\r\n\r\ndef main():\r\n    test_httpx = TestHttpx()\r\n    asyncio.run(test_httpx())\r\n\r\n\r\nif __name__ == '__main__':\r\n    main()\r\n```\n", "before_files": [{"content": "\"\"\"\nHandlers for Content-Encoding.\n\nSee: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding\n\"\"\"\nimport codecs\nimport typing\nimport zlib\n\nimport chardet\n\nfrom ._exceptions import DecodingError\n\ntry:\n    import brotli\nexcept ImportError:  # pragma: nocover\n    brotli = None\n\n\nclass Decoder:\n    def decode(self, data: bytes) -> bytes:\n        raise NotImplementedError()  # pragma: nocover\n\n    def flush(self) -> bytes:\n        raise NotImplementedError()  # pragma: nocover\n\n\nclass IdentityDecoder(Decoder):\n    \"\"\"\n    Handle unencoded data.\n    \"\"\"\n\n    def decode(self, data: bytes) -> bytes:\n        return data\n\n    def flush(self) -> bytes:\n        return b\"\"\n\n\nclass DeflateDecoder(Decoder):\n    \"\"\"\n    Handle 'deflate' decoding.\n\n    See: https://stackoverflow.com/questions/1838699\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.first_attempt = True\n        self.decompressor = zlib.decompressobj()\n\n    def decode(self, data: bytes) -> bytes:\n        was_first_attempt = self.first_attempt\n        self.first_attempt = False\n        try:\n            return self.decompressor.decompress(data)\n        except zlib.error as exc:\n            if was_first_attempt:\n                self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS)\n                return self.decode(data)\n            raise DecodingError from exc\n\n    def flush(self) -> bytes:\n        try:\n            return self.decompressor.flush()\n        except zlib.error as exc:  # pragma: nocover\n            raise DecodingError from exc\n\n\nclass GZipDecoder(Decoder):\n    \"\"\"\n    Handle 'gzip' decoding.\n\n    See: https://stackoverflow.com/questions/1838699\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16)\n\n    def decode(self, data: bytes) -> bytes:\n        try:\n            return self.decompressor.decompress(data)\n        except zlib.error as exc:\n            raise DecodingError from exc\n\n    def flush(self) -> bytes:\n        try:\n            return self.decompressor.flush()\n        except zlib.error as exc:  # pragma: nocover\n            raise DecodingError from exc\n\n\nclass BrotliDecoder(Decoder):\n    \"\"\"\n    Handle 'brotli' decoding.\n\n    Requires `pip install brotlipy`. See: https://brotlipy.readthedocs.io/\n        or   `pip install brotli`. See https://github.com/google/brotli\n    Supports both 'brotlipy' and 'Brotli' packages since they share an import\n    name. The top branches are for 'brotlipy' and bottom branches for 'Brotli'\n    \"\"\"\n\n    def __init__(self) -> None:\n        assert (\n            brotli is not None\n        ), \"The 'brotlipy' or 'brotli' library must be installed to use 'BrotliDecoder'\"\n        self.decompressor = brotli.Decompressor()\n        self.seen_data = False\n        if hasattr(self.decompressor, \"decompress\"):\n            self._decompress = self.decompressor.decompress\n        else:\n            self._decompress = self.decompressor.process  # pragma: nocover\n\n    def decode(self, data: bytes) -> bytes:\n        if not data:\n            return b\"\"\n        self.seen_data = True\n        try:\n            return self._decompress(data)\n        except brotli.error as exc:\n            raise DecodingError from exc\n\n    def flush(self) -> bytes:\n        if not self.seen_data:\n            return b\"\"\n        try:\n            if hasattr(self.decompressor, \"finish\"):\n                self.decompressor.finish()\n            return b\"\"\n        except brotli.error as exc:  # pragma: nocover\n            raise DecodingError from exc\n\n\nclass MultiDecoder(Decoder):\n    \"\"\"\n    Handle the case where multiple encodings have been applied.\n    \"\"\"\n\n    def __init__(self, children: typing.Sequence[Decoder]) -> None:\n        \"\"\"\n        'children' should be a sequence of decoders in the order in which\n        each was applied.\n        \"\"\"\n        # Note that we reverse the order for decoding.\n        self.children = list(reversed(children))\n\n    def decode(self, data: bytes) -> bytes:\n        for child in self.children:\n            data = child.decode(data)\n        return data\n\n    def flush(self) -> bytes:\n        data = b\"\"\n        for child in self.children:\n            data = child.decode(data) + child.flush()\n        return data\n\n\nclass TextDecoder:\n    \"\"\"\n    Handles incrementally decoding bytes into text\n    \"\"\"\n\n    def __init__(self, encoding: typing.Optional[str] = None):\n        self.decoder: typing.Optional[codecs.IncrementalDecoder] = (\n            None if encoding is None else codecs.getincrementaldecoder(encoding)()\n        )\n        self.detector = chardet.universaldetector.UniversalDetector()\n\n        # This buffer is only needed if 'decoder' is 'None'\n        # we want to trigger errors if data is getting added to\n        # our internal buffer for some silly reason while\n        # a decoder is discovered.\n        self.buffer: typing.Optional[bytearray] = None if self.decoder else bytearray()\n\n    def decode(self, data: bytes) -> str:\n        try:\n            if self.decoder is not None:\n                text = self.decoder.decode(data)\n            else:\n                assert self.buffer is not None\n                text = \"\"\n                self.detector.feed(data)\n                self.buffer += data\n\n                # Should be more than enough data to process, we don't\n                # want to buffer too long as chardet will wait until\n                # detector.close() is used to give back common\n                # encodings like 'utf-8'.\n                if len(self.buffer) >= 4096:\n                    self.decoder = codecs.getincrementaldecoder(\n                        self._detector_result()\n                    )()\n                    text = self.decoder.decode(bytes(self.buffer), False)\n                    self.buffer = None\n\n            return text\n        except UnicodeDecodeError:  # pragma: nocover\n            raise DecodingError() from None\n\n    def flush(self) -> str:\n        try:\n            if self.decoder is None:\n                # Empty string case as chardet is guaranteed to not have a guess.\n                assert self.buffer is not None\n                if len(self.buffer) == 0:\n                    return \"\"\n                return bytes(self.buffer).decode(self._detector_result())\n\n            return self.decoder.decode(b\"\", True)\n        except UnicodeDecodeError:  # pragma: nocover\n            raise DecodingError() from None\n\n    def _detector_result(self) -> str:\n        self.detector.close()\n        result = self.detector.result[\"encoding\"]\n        if not result:  # pragma: nocover\n            raise DecodingError(\"Unable to determine encoding of content\")\n\n        return result\n\n\nclass LineDecoder:\n    \"\"\"\n    Handles incrementally reading lines from text.\n\n    Uses universal line decoding, supporting any of `\\n`, `\\r`, or `\\r\\n`\n    as line endings, normalizing to `\\n`.\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.buffer = \"\"\n\n    def decode(self, text: str) -> typing.List[str]:\n        lines = []\n\n        if text.startswith(\"\\n\") and self.buffer and self.buffer[-1] == \"\\r\":\n            # Handle the case where we have an \"\\r\\n\" split across\n            # our previous input, and our new chunk.\n            lines.append(self.buffer[:-1] + \"\\n\")\n            self.buffer = \"\"\n            text = text[1:]\n\n        while text:\n            num_chars = len(text)\n            for idx in range(num_chars):\n                char = text[idx]\n                next_char = None if idx + 1 == num_chars else text[idx + 1]\n                if char == \"\\n\":\n                    lines.append(self.buffer + text[: idx + 1])\n                    self.buffer = \"\"\n                    text = text[idx + 1 :]\n                    break\n                elif char == \"\\r\" and next_char == \"\\n\":\n                    lines.append(self.buffer + text[:idx] + \"\\n\")\n                    self.buffer = \"\"\n                    text = text[idx + 2 :]\n                    break\n                elif char == \"\\r\" and next_char is not None:\n                    lines.append(self.buffer + text[:idx] + \"\\n\")\n                    self.buffer = \"\"\n                    text = text[idx + 1 :]\n                    break\n                elif next_char is None:\n                    self.buffer = text\n                    text = \"\"\n                    break\n\n        return lines\n\n    def flush(self) -> typing.List[str]:\n        if self.buffer.endswith(\"\\r\"):\n            # Handle the case where we had a trailing '\\r', which could have\n            # been a '\\r\\n' pair.\n            lines = [self.buffer[:-1] + \"\\n\"]\n        elif self.buffer:\n            lines = [self.buffer]\n        else:\n            lines = []\n        self.buffer = \"\"\n        return lines\n\n\nSUPPORTED_DECODERS = {\n    \"identity\": IdentityDecoder,\n    \"gzip\": GZipDecoder,\n    \"deflate\": DeflateDecoder,\n    \"br\": BrotliDecoder,\n}\n\n\nif brotli is None:\n    SUPPORTED_DECODERS.pop(\"br\")  # pragma: nocover\n", "path": "httpx/_decoders.py"}], "after_files": [{"content": "\"\"\"\nHandlers for Content-Encoding.\n\nSee: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding\n\"\"\"\nimport codecs\nimport typing\nimport zlib\n\nimport chardet\n\nfrom ._exceptions import DecodingError\n\ntry:\n    import brotli\nexcept ImportError:  # pragma: nocover\n    brotli = None\n\n\nclass Decoder:\n    def decode(self, data: bytes) -> bytes:\n        raise NotImplementedError()  # pragma: nocover\n\n    def flush(self) -> bytes:\n        raise NotImplementedError()  # pragma: nocover\n\n\nclass IdentityDecoder(Decoder):\n    \"\"\"\n    Handle unencoded data.\n    \"\"\"\n\n    def decode(self, data: bytes) -> bytes:\n        return data\n\n    def flush(self) -> bytes:\n        return b\"\"\n\n\nclass DeflateDecoder(Decoder):\n    \"\"\"\n    Handle 'deflate' decoding.\n\n    See: https://stackoverflow.com/questions/1838699\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.first_attempt = True\n        self.decompressor = zlib.decompressobj()\n\n    def decode(self, data: bytes) -> bytes:\n        was_first_attempt = self.first_attempt\n        self.first_attempt = False\n        try:\n            return self.decompressor.decompress(data)\n        except zlib.error as exc:\n            if was_first_attempt:\n                self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS)\n                return self.decode(data)\n            raise DecodingError from exc\n\n    def flush(self) -> bytes:\n        try:\n            return self.decompressor.flush()\n        except zlib.error as exc:  # pragma: nocover\n            raise DecodingError from exc\n\n\nclass GZipDecoder(Decoder):\n    \"\"\"\n    Handle 'gzip' decoding.\n\n    See: https://stackoverflow.com/questions/1838699\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16)\n\n    def decode(self, data: bytes) -> bytes:\n        try:\n            return self.decompressor.decompress(data)\n        except zlib.error as exc:\n            raise DecodingError from exc\n\n    def flush(self) -> bytes:\n        try:\n            return self.decompressor.flush()\n        except zlib.error as exc:  # pragma: nocover\n            raise DecodingError from exc\n\n\nclass BrotliDecoder(Decoder):\n    \"\"\"\n    Handle 'brotli' decoding.\n\n    Requires `pip install brotlipy`. See: https://brotlipy.readthedocs.io/\n        or   `pip install brotli`. See https://github.com/google/brotli\n    Supports both 'brotlipy' and 'Brotli' packages since they share an import\n    name. The top branches are for 'brotlipy' and bottom branches for 'Brotli'\n    \"\"\"\n\n    def __init__(self) -> None:\n        assert (\n            brotli is not None\n        ), \"The 'brotlipy' or 'brotli' library must be installed to use 'BrotliDecoder'\"\n        self.decompressor = brotli.Decompressor()\n        self.seen_data = False\n        if hasattr(self.decompressor, \"decompress\"):\n            self._decompress = self.decompressor.decompress\n        else:\n            self._decompress = self.decompressor.process  # pragma: nocover\n\n    def decode(self, data: bytes) -> bytes:\n        if not data:\n            return b\"\"\n        self.seen_data = True\n        try:\n            return self._decompress(data)\n        except brotli.error as exc:\n            raise DecodingError from exc\n\n    def flush(self) -> bytes:\n        if not self.seen_data:\n            return b\"\"\n        try:\n            if hasattr(self.decompressor, \"finish\"):\n                self.decompressor.finish()\n            return b\"\"\n        except brotli.error as exc:  # pragma: nocover\n            raise DecodingError from exc\n\n\nclass MultiDecoder(Decoder):\n    \"\"\"\n    Handle the case where multiple encodings have been applied.\n    \"\"\"\n\n    def __init__(self, children: typing.Sequence[Decoder]) -> None:\n        \"\"\"\n        'children' should be a sequence of decoders in the order in which\n        each was applied.\n        \"\"\"\n        # Note that we reverse the order for decoding.\n        self.children = list(reversed(children))\n\n    def decode(self, data: bytes) -> bytes:\n        for child in self.children:\n            data = child.decode(data)\n        return data\n\n    def flush(self) -> bytes:\n        data = b\"\"\n        for child in self.children:\n            data = child.decode(data) + child.flush()\n        return data\n\n\nclass TextDecoder:\n    \"\"\"\n    Handles incrementally decoding bytes into text\n    \"\"\"\n\n    def __init__(self, encoding: typing.Optional[str] = None):\n        self.decoder: typing.Optional[codecs.IncrementalDecoder] = (\n            None if encoding is None else codecs.getincrementaldecoder(encoding)()\n        )\n        self.detector = chardet.universaldetector.UniversalDetector()\n\n        # This buffer is only needed if 'decoder' is 'None'\n        # we want to trigger errors if data is getting added to\n        # our internal buffer for some silly reason while\n        # a decoder is discovered.\n        self.buffer: typing.Optional[bytearray] = None if self.decoder else bytearray()\n\n    def decode(self, data: bytes) -> str:\n        try:\n            if self.decoder is not None:\n                text = self.decoder.decode(data)\n            else:\n                assert self.buffer is not None\n                text = \"\"\n                self.detector.feed(data)\n                self.buffer += data\n\n                # Should be more than enough data to process, we don't\n                # want to buffer too long as chardet will wait until\n                # detector.close() is used to give back common\n                # encodings like 'utf-8'.\n                if len(self.buffer) >= 4096:\n                    self.decoder = codecs.getincrementaldecoder(\n                        self._detector_result()\n                    )()\n                    text = self.decoder.decode(bytes(self.buffer), False)\n                    self.buffer = None\n\n            return text\n        except UnicodeDecodeError:  # pragma: nocover\n            raise DecodingError() from None\n\n    def flush(self) -> str:\n        try:\n            if self.decoder is None:\n                # Empty string case as chardet is guaranteed to not have a guess.\n                assert self.buffer is not None\n                if len(self.buffer) == 0:\n                    return \"\"\n                return bytes(self.buffer).decode(self._detector_result())\n\n            return self.decoder.decode(b\"\", True)\n        except UnicodeDecodeError:  # pragma: nocover\n            raise DecodingError() from None\n\n    def _detector_result(self) -> str:\n        self.detector.close()\n        result = self.detector.result[\"encoding\"]\n        if not result:  # pragma: nocover\n            raise DecodingError(\"Unable to determine encoding of content\")\n\n        return result\n\n\nclass LineDecoder:\n    \"\"\"\n    Handles incrementally reading lines from text.\n\n    Uses universal line decoding, supporting any of `\\n`, `\\r`, or `\\r\\n`\n    as line endings, normalizing to `\\n`.\n    \"\"\"\n\n    def __init__(self) -> None:\n        self.buffer = \"\"\n\n    def decode(self, text: str) -> typing.List[str]:\n        lines = []\n\n        if text.startswith(\"\\n\") and self.buffer and self.buffer[-1] == \"\\r\":\n            # Handle the case where we have an \"\\r\\n\" split across\n            # our previous input, and our new chunk.\n            lines.append(self.buffer[:-1] + \"\\n\")\n            self.buffer = \"\"\n            text = text[1:]\n\n        while text:\n            num_chars = len(text)\n            for idx in range(num_chars):\n                char = text[idx]\n                next_char = None if idx + 1 == num_chars else text[idx + 1]\n                if char == \"\\n\":\n                    lines.append(self.buffer + text[: idx + 1])\n                    self.buffer = \"\"\n                    text = text[idx + 1 :]\n                    break\n                elif char == \"\\r\" and next_char == \"\\n\":\n                    lines.append(self.buffer + text[:idx] + \"\\n\")\n                    self.buffer = \"\"\n                    text = text[idx + 2 :]\n                    break\n                elif char == \"\\r\" and next_char is not None:\n                    lines.append(self.buffer + text[:idx] + \"\\n\")\n                    self.buffer = \"\"\n                    text = text[idx + 1 :]\n                    break\n                elif next_char is None:\n                    self.buffer += text\n                    text = \"\"\n                    break\n\n        return lines\n\n    def flush(self) -> typing.List[str]:\n        if self.buffer.endswith(\"\\r\"):\n            # Handle the case where we had a trailing '\\r', which could have\n            # been a '\\r\\n' pair.\n            lines = [self.buffer[:-1] + \"\\n\"]\n        elif self.buffer:\n            lines = [self.buffer]\n        else:\n            lines = []\n        self.buffer = \"\"\n        return lines\n\n\nSUPPORTED_DECODERS = {\n    \"identity\": IdentityDecoder,\n    \"gzip\": GZipDecoder,\n    \"deflate\": DeflateDecoder,\n    \"br\": BrotliDecoder,\n}\n\n\nif brotli is None:\n    SUPPORTED_DECODERS.pop(\"br\")  # pragma: nocover\n", "path": "httpx/_decoders.py"}]}