Avoid compressing binary images on ingress ()

pull/95729/head^2
J. Nick Koston 2023-07-15 00:09:25 -10:00 committed by GitHub
parent a27e126c86
commit 62c5194bc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 3 deletions
homeassistant/components/hassio
tests/components/hassio

View File

@ -177,7 +177,8 @@ class HassIOView(HomeAssistantView):
) )
response.content_type = client.content_type response.content_type = client.content_type
response.enable_compression() if should_compress(response.content_type):
response.enable_compression()
await response.prepare(request) await response.prepare(request)
async for data in client.content.iter_chunked(8192): async for data in client.content.iter_chunked(8192):
await response.write(data) await response.write(data)
@ -213,3 +214,10 @@ def _get_timeout(path: str) -> ClientTimeout:
if NO_TIMEOUT.match(path): if NO_TIMEOUT.match(path):
return ClientTimeout(connect=10, total=None) return ClientTimeout(connect=10, total=None)
return ClientTimeout(connect=10, total=300) return ClientTimeout(connect=10, total=300)
def should_compress(content_type: str) -> bool:
"""Return if we should compress a response."""
if content_type.startswith("image/"):
return "svg" in content_type
return not content_type.startswith(("video/", "audio/", "font/"))

View File

@ -20,6 +20,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import UNDEFINED from homeassistant.helpers.typing import UNDEFINED
from .const import X_HASS_SOURCE, X_INGRESS_PATH from .const import X_HASS_SOURCE, X_INGRESS_PATH
from .http import should_compress
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -182,7 +183,9 @@ class HassIOIngress(HomeAssistantView):
content_type=result.content_type, content_type=result.content_type,
body=body, body=body,
) )
if content_length_int > MIN_COMPRESSED_SIZE: if content_length_int > MIN_COMPRESSED_SIZE and should_compress(
simple_response.content_type
):
simple_response.enable_compression() simple_response.enable_compression()
await simple_response.prepare(request) await simple_response.prepare(request)
return simple_response return simple_response
@ -192,7 +195,8 @@ class HassIOIngress(HomeAssistantView):
response.content_type = result.content_type response.content_type = result.content_type
try: try:
response.enable_compression() if should_compress(response.content_type):
response.enable_compression()
await response.prepare(request) await response.prepare(request)
async for data in result.content.iter_chunked(8192): async for data in result.content.iter_chunked(8192):
await response.write(data) await response.write(data)

View File

@ -396,6 +396,68 @@ async def test_ingress_request_get_compressed(
assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO] assert aioclient_mock.mock_calls[-1][3][X_FORWARDED_PROTO]
@pytest.mark.parametrize(
"content_type",
[
"image/png",
"image/jpeg",
"font/woff2",
"video/mp4",
],
)
async def test_ingress_request_not_compressed(
hassio_noauth_client, content_type: str, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test ingress does not compress images."""
body = b"this_is_long_enough_to_be_compressed" * 100
aioclient_mock.get(
"http://127.0.0.1/ingress/core/x.any",
data=body,
headers={"Content-Length": len(body), "Content-Type": content_type},
)
resp = await hassio_noauth_client.get(
"/api/hassio_ingress/core/x.any",
headers={"X-Test-Header": "beer", "Accept-Encoding": "gzip, deflate"},
)
# Check we got right response
assert resp.status == HTTPStatus.OK
assert resp.headers["Content-Type"] == content_type
assert "Content-Encoding" not in resp.headers
@pytest.mark.parametrize(
"content_type",
[
"image/svg+xml",
"text/html",
"application/javascript",
"text/plain",
],
)
async def test_ingress_request_compressed(
hassio_noauth_client, content_type: str, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test ingress compresses text."""
body = b"this_is_long_enough_to_be_compressed" * 100
aioclient_mock.get(
"http://127.0.0.1/ingress/core/x.any",
data=body,
headers={"Content-Length": len(body), "Content-Type": content_type},
)
resp = await hassio_noauth_client.get(
"/api/hassio_ingress/core/x.any",
headers={"X-Test-Header": "beer", "Accept-Encoding": "gzip, deflate"},
)
# Check we got right response
assert resp.status == HTTPStatus.OK
assert resp.headers["Content-Type"] == content_type
assert resp.headers["Content-Encoding"] == "deflate"
@pytest.mark.parametrize( @pytest.mark.parametrize(
"build_type", "build_type",
[ [