Skip to content

Commit 616a23e

Browse files
committed
Bypass GZipMiddleware when response includes Content-Encoding
Closes #4 Refs Kludex/starlette#1901 Credit for this change goes to https://github.com/Kludex and https://github.com/kklingenberg
1 parent 5eae07a commit 616a23e

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

asgi_gzip/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def __init__(self, app, minimum_size: int, compresslevel: int = 9) -> None:
3030
self.send = unattached_send
3131
self.initial_message = {}
3232
self.started = False
33+
self.content_encoding_set = False
3334
self.gzip_buffer = io.BytesIO()
3435
self.gzip_file = gzip.GzipFile(
3536
mode="wb", fileobj=self.gzip_buffer, compresslevel=compresslevel
@@ -45,6 +46,13 @@ async def send_with_gzip(self, message) -> None:
4546
# Don't send the initial message until we've determined how to
4647
# modify the outgoing headers correctly.
4748
self.initial_message = message
49+
headers = Headers(raw=self.initial_message["headers"])
50+
self.content_encoding_set = "content-encoding" in headers
51+
elif message_type == "http.response.body" and self.content_encoding_set:
52+
if not self.started:
53+
self.started = True
54+
await self.send(self.initial_message)
55+
await self.send(message)
4856
elif message_type == "http.response.body" and not self.started:
4957
self.started = True
5058
body = message.get("body", b"")

tests/test_asgi_gzip.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,27 @@ async def generator(bytes, count):
7676
assert response.text == "x" * 4000
7777
assert response.headers["Content-Encoding"] == "gzip"
7878
assert "Content-Length" not in response.headers
79+
80+
81+
def test_gzip_ignored_for_responses_with_encoding_set(test_client_factory):
82+
def homepage(request):
83+
async def generator(bytes, count):
84+
for index in range(count):
85+
yield bytes
86+
87+
streaming = generator(bytes=b"x" * 400, count=10)
88+
return StreamingResponse(
89+
streaming, status_code=200, headers={"Content-Encoding": "br"}
90+
)
91+
92+
app = Starlette(
93+
routes=[Route("/", endpoint=homepage)],
94+
middleware=[Middleware(GZipMiddleware)],
95+
)
96+
97+
client = test_client_factory(app)
98+
response = client.get("/", headers={"accept-encoding": "gzip, br"})
99+
assert response.status_code == 200
100+
assert response.text == "x" * 4000
101+
assert response.headers["Content-Encoding"] == "br"
102+
assert "Content-Length" not in response.headers

0 commit comments

Comments
 (0)