Decoder support
This commit is contained in:
parent
665743aedb
commit
fcc1fe1233
@ -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()
|
||||
|
||||
41
httpcore/decoders.py
Normal file
41
httpcore/decoders.py
Normal file
@ -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
|
||||
Loading…
Reference in New Issue
Block a user