From: Yeray Diaz Diaz Date: Fri, 26 Apr 2019 19:09:57 +0000 (+0100) Subject: Wrap decoding errors with custom exceptions X-Git-Tag: 0.3.0~65^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bdc218f8e686a2936c4069b00acde66391eaaf4c;p=thirdparty%2Fhttpx.git Wrap decoding errors with custom exceptions --- diff --git a/httpcore/__init__.py b/httpcore/__init__.py index 9824e854..7786c259 100644 --- a/httpcore/__init__.py +++ b/httpcore/__init__.py @@ -9,6 +9,9 @@ from .exceptions import ( ResponseClosed, StreamConsumed, Timeout, + DeflateDecodingError, + GzipDecodingError, + BrotliDecodingError, ) from .http11 import HTTP11Connection from .sync import SyncClient, SyncConnectionPool diff --git a/httpcore/decoders.py b/httpcore/decoders.py index b56745c4..dc56e131 100644 --- a/httpcore/decoders.py +++ b/httpcore/decoders.py @@ -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: diff --git a/httpcore/exceptions.py b/httpcore/exceptions.py index 30814332..a85f128f 100644 --- a/httpcore/exceptions.py +++ b/httpcore/exceptions.py @@ -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. + """ diff --git a/tests/test_decoding.py b/tests/test_decoding.py index f08c0abf..c4a17466 100644 --- a/tests/test_decoding.py +++ b/tests/test_decoding.py @@ -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)