Skip to content

Commit 9c550bf

Browse files
authored
Don't compress 206 Partial Content responses (#677)
1 parent e022cd3 commit 9c550bf

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

lib/bandit/compression.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ defmodule Bandit.Compression do
7777

7878
headers = maybe_add_vary_header(adapter, status, headers)
7979

80-
if status not in [204, 304] && not is_nil(adapter.content_encoding) &&
80+
# 206 responses are excluded since compressing them would change the bytes relative to the
81+
# content-range the response advertises against the identity representation, corrupting
82+
# range reassembly at the client
83+
if status not in [204, 206, 304] && not is_nil(adapter.content_encoding) &&
8184
is_nil(response_content_encoding_header) &&
8285
!response_has_strong_etag(headers) && !response_indicates_no_transform(headers) &&
8386
!empty_body? do

test/bandit/http1/protocol_test.exs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,21 @@ defmodule HTTP1ProtocolTest do
19921992
assert response.body == String.duplicate("a", 10_000)
19931993
end
19941994

1995+
test "does no encoding for 206 responses", context do
1996+
response =
1997+
Req.get!(context.req,
1998+
url: "/send_206_response",
1999+
headers: [{"accept-encoding", "deflate"}]
2000+
)
2001+
2002+
# Assert that we did not try to compress the body, since doing so would
2003+
# invalidate the range the response advertises via content-range
2004+
assert response.status == 206
2005+
assert response.headers["content-length"] == ["10000"]
2006+
assert response.headers["content-encoding"] == nil
2007+
assert response.body == String.duplicate("a", 10_000)
2008+
end
2009+
19952010
test "does no encoding if a malformed etag starting with W but not W/ is present", context do
19962011
response =
19972012
Req.get!(context.req,
@@ -2216,6 +2231,12 @@ defmodule HTTP1ProtocolTest do
22162231
|> send_resp(200, String.duplicate("a", 10_000))
22172232
end
22182233

2234+
def send_206_response(conn) do
2235+
conn
2236+
|> put_resp_header("content-range", "bytes 0-9999/20000")
2237+
|> send_resp(206, String.duplicate("a", 10_000))
2238+
end
2239+
22192240
def send_weak_etag(conn) do
22202241
conn
22212242
|> put_resp_header("etag", "W/\"1234\"")

0 commit comments

Comments
 (0)