SSLConfig,
TimeoutConfig,
)
+from .decoders import IdentityDecoder
from .exceptions import ResponseClosed, StreamConsumed
self.on_close = on_close
self.is_closed = False
self.is_streamed = False
+ self.decoder = IdentityDecoder()
if isinstance(body, bytes):
self.is_closed = True
self.body = body
self.body_aiter = body
async def read(self) -> bytes:
+ """
+ Read and return the response content.
+ """
if not hasattr(self, "body"):
body = b""
async for part in self.stream():
self.body = body
return self.body
- async def stream(self) -> typing.AsyncIterator[bytes]:
+ async def stream(self):
+ """
+ A byte-iterator over the decoded response content.
+ This will allow us to handle gzip, deflate, and brotli encoded responses.
+ """
if hasattr(self, "body"):
yield self.body
else:
- if self.is_streamed:
- raise StreamConsumed()
- if self.is_closed:
- raise ResponseClosed()
- self.is_streamed = True
- async for part in self.body_aiter():
- yield part
- await self.close()
+ async for chunk in self.raw():
+ yield self.decoder.decode(chunk)
+ yield self.decoder.flush()
+
+ async def raw(self) -> typing.AsyncIterator[bytes]:
+ """
+ A byte-iterator over the raw response content.
+ """
+ if self.is_streamed:
+ raise StreamConsumed()
+ if self.is_closed:
+ raise ResponseClosed()
+ self.is_streamed = True
+ async for part in self.body_aiter():
+ yield part
+ await self.close()
async def close(self) -> None:
if not self.is_closed:
self.is_closed = True
if self.on_close is not None:
await self.on_close()
-
- async def __aenter__(self) -> "Response":
- return self
-
- async def __aexit__(
- self,
- exc_type: typing.Type[BaseException] = None,
- exc_value: BaseException = None,
- traceback: TracebackType = None,
- ) -> None:
- if not self.is_closed:
- await self.close()
--- /dev/null
+"""
+Handlers for Content-Encoding.
+"""
+
+
+class IdentityDecoder:
+ def decode(self, chunk: bytes) -> bytes:
+ return chunk
+
+ def flush(self) -> bytes:
+ return b''
+
+
+# class DeflateDecoder:
+# pass
+#
+#
+# class GZipDecoder:
+# pass
+#
+#
+# class BrotliDecoder:
+# pass
+#
+#
+# class MultiDecoder:
+# def __init__(self, children):
+# self.children = children
+#
+# def decode(self, chunk: bytes) -> bytes:
+# data = chunk
+# for child in children:
+# data = child.decode(data)
+# return data
+#
+# def flush(self) -> bytes:
+# data = b''
+# for child in children:
+# data = child.decode(data)
+# data = child.flush()
+# return data