Skip to content

Commit dd9c39d

Browse files
committed
feat: improve decompression middleware
closes #598
1 parent cfee71b commit dd9c39d

File tree

5 files changed

+37
-7
lines changed

5 files changed

+37
-7
lines changed

lib/tesla/middleware.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ defmodule Tesla.Middleware do
1616
Tesla.client([{Tesla.Middleware.BaseUrl, "https://example.com"}])
1717
1818
## Ordering
19-
19+
2020
The order in which middleware is defined matters. Note that the order when _sending_ the request
2121
matches the order the middleware was defined in, but the order when _receiving_ the response
2222
is reversed.
23-
23+
2424
For example, `Tesla.Middleware.DecompressResponse` must come _after_ `Tesla.Middleware.JSON`,
2525
otherwise the response isn't decompressed before it reaches the JSON parser.
2626

lib/tesla/middleware/compression.ex

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,19 @@ defmodule Tesla.Middleware.Compression do
6161
def decompress({:error, reason}), do: {:error, reason}
6262

6363
def decompress(env) do
64+
body = decompress_body(env.body, Tesla.get_header(env, "content-encoding"))
65+
66+
content_length =
67+
body
68+
|> byte_size()
69+
|> to_string()
70+
6471
env
65-
|> Tesla.put_body(decompress_body(env.body, Tesla.get_header(env, "content-encoding")))
72+
|> Tesla.put_body(body)
73+
# what should happen if the content-encoding is not supported and the body
74+
# is not decompressed?
75+
|> Tesla.delete_header("content-encoding")
76+
|> Tesla.put_header("content-length", content_length)
6677
end
6778

6879
defp decompress_body(<<31, 139, 8, _::binary>> = body, "gzip"), do: :zlib.gunzip(body)

lib/tesla/middleware/json.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ defmodule Tesla.Middleware.DecodeJson do
164164
"""
165165
@moduledoc since: "1.8.0"
166166

167+
@behaviour Tesla.Middleware
168+
167169
@impl Tesla.Middleware
168170
def call(env, next, opts) do
169171
opts = opts || []
@@ -180,6 +182,8 @@ defmodule Tesla.Middleware.EncodeJson do
180182
"""
181183
@moduledoc since: "1.8.0"
182184

185+
@behaviour Tesla.Middleware
186+
183187
@impl Tesla.Middleware
184188
def call(env, next, opts) do
185189
opts = opts || []

test/support/test_support.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
defmodule TestSupport do
2+
def gzip_headers(env) do
3+
env.headers
4+
|> Enum.map_join("|", fn {key, value} -> "#{key}: #{value}" end)
5+
|> :zlib.gzip()
6+
end
7+
end

test/tesla/middleware/compression_test.exs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,14 @@ defmodule Tesla.Middleware.CompressionTest do
6767
end
6868
end
6969

70+
test "decompress response body update the headers correctly" do
71+
assert {:ok, env} = CompressionResponseClient.get("/response-gzip")
72+
assert env.headers == [{"content-type", "text/plain"}, {"content-length", "17"}]
73+
end
74+
7075
test "decompress response body (gzip)" do
7176
assert {:ok, env} = CompressionResponseClient.get("/response-gzip")
77+
assert env.headers == [{"content-type", "text/plain"}, {"content-length", "17"}]
7278
assert env.body == "decompressed gzip"
7379
end
7480

@@ -114,7 +120,8 @@ defmodule Tesla.Middleware.CompressionTest do
114120
{status, headers, body} =
115121
case env.url do
116122
"/" ->
117-
{200, [{"content-type", "text/plain"}, {"content-encoding", "gzip"}], env.headers}
123+
{200, [{"content-type", "text/plain"}, {"content-encoding", "gzip"}],
124+
TestSupport.gzip_headers(env)}
118125
end
119126

120127
{:ok, %{env | status: status, headers: headers, body: body}}
@@ -123,7 +130,7 @@ defmodule Tesla.Middleware.CompressionTest do
123130

124131
test "Compression headers" do
125132
assert {:ok, env} = CompressionHeadersClient.get("/")
126-
assert env.body == [{"accept-encoding", "gzip, deflate"}]
133+
assert env.body == "accept-encoding: gzip, deflate"
127134
end
128135

129136
defmodule DecompressResponseHeadersClient do
@@ -135,7 +142,8 @@ defmodule Tesla.Middleware.CompressionTest do
135142
{status, headers, body} =
136143
case env.url do
137144
"/" ->
138-
{200, [{"content-type", "text/plain"}, {"content-encoding", "gzip"}], env.headers}
145+
{200, [{"content-type", "text/plain"}, {"content-encoding", "gzip"}],
146+
TestSupport.gzip_headers(env)}
139147
end
140148

141149
{:ok, %{env | status: status, headers: headers, body: body}}
@@ -144,7 +152,7 @@ defmodule Tesla.Middleware.CompressionTest do
144152

145153
test "Decompress response headers" do
146154
assert {:ok, env} = DecompressResponseHeadersClient.get("/")
147-
assert env.body == [{"accept-encoding", "gzip, deflate"}]
155+
assert env.body == "accept-encoding: gzip, deflate"
148156
end
149157

150158
defmodule CompressRequestHeadersClient do

0 commit comments

Comments
 (0)