Skip to content

Commit

Permalink
Don't automatically compress when response has etag
Browse files Browse the repository at this point in the history
In the cowboy_compress_h stream handler.

Otherwise this could cause issues with caching, with the
etag being the same for compressed/uncompressed content.

Users that wish to send etags AND compress will have to
do it manually for the time being.
  • Loading branch information
essen committed Jan 5, 2024
1 parent 67df6fe commit 5b2f600
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 1 deletion.
4 changes: 3 additions & 1 deletion doc/src/manual/cowboy_compress_h.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ cowboy_compress_h - Compress stream handler
The module `cowboy_compress_h` compresses response bodies
automatically when the client supports it. It will not
try to compress responses that already have a content
encoding.
encoding or that have an etag header defined.

Normal responses will only be compressed when their
size is lower than the configured threshold. Streamed
Expand Down Expand Up @@ -55,6 +55,8 @@ The compress stream handler does not produce any event.

== Changelog

* *2.11*: Compression is now disabled when the etag
header is in the response headers.
* *2.6*: The options `compress_buffering` and
`compress_threshold` were added.
* *2.0*: Module introduced.
Expand Down
3 changes: 3 additions & 0 deletions src/cowboy_compress_h.erl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ check_req(Req) ->
%% Do not compress responses that contain the content-encoding header.
check_resp_headers(#{<<"content-encoding">> := _}, State) ->
State#state{compress=undefined};
%% Do not compress responses that contain the etag header.
check_resp_headers(#{<<"etag">> := _}, State) ->
State#state{compress=undefined};
check_resp_headers(_, State) ->
State.

Expand Down
20 changes: 20 additions & 0 deletions test/compress_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ gzip_reply_content_encoding(Config) ->
{_, <<"100000">>} = lists:keyfind(<<"content-length">>, 1, Headers),
ok.

gzip_reply_etag(Config) ->
doc("Reply with etag header; get an uncompressed response."),
{200, Headers, _} = do_get("/reply/etag",
[{<<"accept-encoding">>, <<"gzip">>}], Config),
%% We set a strong etag.
{_, <<"\"STRONK\"">>} = lists:keyfind(<<"etag">>, 1, Headers),
%% The reply didn't include a vary header.
false = lists:keyfind(<<"vary">>, 1, Headers),
{_, <<"100000">>} = lists:keyfind(<<"content-length">>, 1, Headers),
ok.

gzip_reply_large_body(Config) ->
doc("Reply a large body; get a gzipped response."),
{200, Headers, GzBody} = do_get("/reply/large",
Expand Down Expand Up @@ -174,6 +185,15 @@ gzip_stream_reply_content_encoding(Config) ->
100000 = iolist_size(Body),
ok.

gzip_stream_reply_etag(Config) ->
doc("Stream reply with etag header; get an uncompressed response."),
{200, Headers, Body} = do_get("/stream_reply/etag",
[{<<"accept-encoding">>, <<"gzip">>}], Config),
{_, <<"\"STRONK\"">>} = lists:keyfind(<<"etag">>, 1, Headers),
false = lists:keyfind(<<"vary">>, 1, Headers),
100000 = iolist_size(Body),
ok.

opts_compress_buffering_false(Config0) ->
doc("Confirm that the compress_buffering option can be set to false, "
"which is the default."),
Expand Down
5 changes: 5 additions & 0 deletions test/handlers/compress_h.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ init(Req0, State=reply) ->
<<"content-encoding">> ->
cowboy_req:reply(200, #{<<"content-encoding">> => <<"compress">>},
lists:duplicate(100000, $a), Req0);
<<"etag">> ->
cowboy_req:reply(200, #{<<"etag">> => <<"\"STRONK\"">>},
lists:duplicate(100000, $a), Req0);
<<"sendfile">> ->
AppFile = code:where_is_file("cowboy.app"),
Size = filelib:file_size(AppFile),
Expand All @@ -34,6 +37,8 @@ init(Req0, State=stream_reply) ->
stream_reply(#{}, Req0);
<<"content-encoding">> ->
stream_reply(#{<<"content-encoding">> => <<"compress">>}, Req0);
<<"etag">> ->
stream_reply(#{<<"etag">> => <<"\"STRONK\"">>}, Req0);
<<"sendfile">> ->
Data = lists:duplicate(10000, $a),
AppFile = code:where_is_file("cowboy.app"),
Expand Down

0 comments on commit 5b2f600

Please sign in to comment.