Wrap decoding errors with custom exceptions
This commit is contained in:
parent
91a2a1b896
commit
bdc218f8e6
@ -9,6 +9,9 @@ from .exceptions import (
|
||||
ResponseClosed,
|
||||
StreamConsumed,
|
||||
Timeout,
|
||||
DeflateDecodingError,
|
||||
GzipDecodingError,
|
||||
BrotliDecodingError,
|
||||
)
|
||||
from .http11 import HTTP11Connection
|
||||
from .sync import SyncClient, SyncConnectionPool
|
||||
|
||||
@ -12,6 +12,9 @@ except ImportError: # pragma: nocover
|
||||
brotli = None
|
||||
|
||||
|
||||
import httpcore.exceptions
|
||||
|
||||
|
||||
class Decoder:
|
||||
def decode(self, data: bytes) -> bytes:
|
||||
raise NotImplementedError() # pragma: nocover
|
||||
@ -39,10 +42,16 @@ class DeflateDecoder(Decoder):
|
||||
self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
|
||||
|
||||
def decode(self, data: bytes) -> bytes:
|
||||
return self.decompressor.decompress(data)
|
||||
try:
|
||||
return self.decompressor.decompress(data)
|
||||
except zlib.error as exc:
|
||||
raise httpcore.exceptions.DeflateDecodingError from exc
|
||||
|
||||
def flush(self) -> bytes:
|
||||
return self.decompressor.flush()
|
||||
try:
|
||||
return self.decompressor.flush()
|
||||
except zlib.error as exc:
|
||||
raise httpcore.exceptions.DeflateDecodingError from exc
|
||||
|
||||
|
||||
class GZipDecoder(Decoder):
|
||||
@ -56,10 +65,16 @@ class GZipDecoder(Decoder):
|
||||
self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16)
|
||||
|
||||
def decode(self, data: bytes) -> bytes:
|
||||
return self.decompressor.decompress(data)
|
||||
try:
|
||||
return self.decompressor.decompress(data)
|
||||
except zlib.error as exc:
|
||||
raise httpcore.exceptions.GzipDecodingError from exc
|
||||
|
||||
def flush(self) -> bytes:
|
||||
return self.decompressor.flush()
|
||||
try:
|
||||
return self.decompressor.flush()
|
||||
except zlib.error as exc:
|
||||
raise httpcore.exceptions.GzipDecodingError from exc
|
||||
|
||||
|
||||
class BrotliDecoder(Decoder):
|
||||
@ -77,16 +92,22 @@ class BrotliDecoder(Decoder):
|
||||
self.decompressor = brotli.Decompressor()
|
||||
|
||||
def decode(self, data: bytes) -> bytes:
|
||||
return self.decompressor.decompress(data)
|
||||
try:
|
||||
return self.decompressor.decompress(data)
|
||||
except brotli.Error as exc:
|
||||
raise httpcore.exceptions.BrotliDecodingError from exc
|
||||
|
||||
def flush(self) -> bytes:
|
||||
self.decompressor.finish()
|
||||
return b""
|
||||
try:
|
||||
self.decompressor.finish()
|
||||
return b""
|
||||
except brotli.Error as exc:
|
||||
raise httpcore.exceptions.BrotliDecodingError from exc
|
||||
|
||||
|
||||
class MultiDecoder(Decoder):
|
||||
"""
|
||||
Handle the case where mutliple encodings have been applied.
|
||||
Handle the case where mutiple encodings have been applied.
|
||||
"""
|
||||
|
||||
def __init__(self, children: typing.Sequence[Decoder]) -> None:
|
||||
|
||||
@ -40,3 +40,27 @@ class ResponseClosed(Exception):
|
||||
Attempted to read or stream response content, but the request has been
|
||||
closed without loading the body.
|
||||
"""
|
||||
|
||||
|
||||
class DecodingError(Exception):
|
||||
"""
|
||||
Decoding of the response failed.
|
||||
"""
|
||||
|
||||
|
||||
class DeflateDecodingError(DecodingError):
|
||||
"""
|
||||
Decoding of the response using deflate failed.
|
||||
"""
|
||||
|
||||
|
||||
class GzipDecodingError(DecodingError):
|
||||
"""
|
||||
Decoding of the response using gzip failed.
|
||||
"""
|
||||
|
||||
|
||||
class BrotliDecodingError(DecodingError):
|
||||
"""
|
||||
Decoding of the response using brotli failed.
|
||||
"""
|
||||
|
||||
@ -77,3 +77,18 @@ async def test_streaming():
|
||||
response = httpcore.Response(200, headers=headers, body=compress(body))
|
||||
assert not hasattr(response, "body")
|
||||
assert await response.read() == body
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'header_value, expected_exception',
|
||||
[
|
||||
(b"deflate", httpcore.DeflateDecodingError),
|
||||
(b"gzip", httpcore.GzipDecodingError),
|
||||
(b"br", httpcore.BrotliDecodingError),
|
||||
])
|
||||
def test_decoding_errors(header_value, expected_exception):
|
||||
headers = [(b"Content-Encoding", header_value)]
|
||||
body = b"test 123"
|
||||
compressed_body = brotli.compress(body)[3:]
|
||||
with pytest.raises(expected_exception):
|
||||
response = httpcore.Response(200, headers=headers, body=compressed_body)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user