From: Tom Christie Date: Fri, 5 Apr 2019 16:16:12 +0000 (+0100) Subject: Decoder support X-Git-Tag: 0.0.3~1^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fcc1fe1233c5a47d65ba6d39619a16873efafc70;p=thirdparty%2Fhttpx.git Decoder support --- diff --git a/httpcore/api.py b/httpcore/api.py index c270d569..e8bb5d98 100644 --- a/httpcore/api.py +++ b/httpcore/api.py @@ -9,6 +9,7 @@ from .config import ( SSLConfig, TimeoutConfig, ) +from .decoders import IdentityDecoder from .exceptions import ResponseClosed, StreamConsumed @@ -86,6 +87,7 @@ class Response: 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 @@ -93,6 +95,9 @@ class Response: 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(): @@ -100,33 +105,33 @@ class Response: 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() diff --git a/httpcore/decoders.py b/httpcore/decoders.py new file mode 100644 index 00000000..09b9336b --- /dev/null +++ b/httpcore/decoders.py @@ -0,0 +1,41 @@ +""" +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