Packages
tesla
1.13.2
1.20.0
1.18.3
1.18.2
1.18.1
1.18.0
1.17.0
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.1
1.14.0
1.13.2
1.13.1
1.13.0
1.12.3
1.12.2
1.12.1
1.12.0
1.11.2
1.11.1
1.11.0
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.1
retired
1.8.0
1.7.0
1.6.1
1.6.0
1.5.1
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.0
1.0.0-beta.1
0.10.0
0.9.0
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.2.2
0.2.1
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
HTTP client library, with support for middleware and multiple adapters.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/tesla/middleware/compression.ex
defmodule Tesla.Middleware.Compression do
@moduledoc """
Compress requests and decompress responses.
Supports "gzip" and "deflate" encodings using Erlang's built-in `:zlib` module.
## Examples
```elixir
defmodule MyClient do
def client do
Tesla.client([
{Tesla.Middleware.Compression, format: "gzip"}
])
end
end
```
## Options
- `:format` - request compression format, `"gzip"` (default) or `"deflate"`
"""
@behaviour Tesla.Middleware
@impl Tesla.Middleware
def call(env, next, opts) do
env
|> compress(opts)
|> add_accept_encoding()
|> Tesla.run(next)
|> decompress()
end
@doc false
def add_accept_encoding(env) do
Tesla.put_headers(env, [{"accept-encoding", "gzip, deflate, identity"}])
end
defp compressible?(body), do: is_binary(body)
@doc """
Compress request.
It is used by `Tesla.Middleware.CompressRequest`.
"""
def compress(env, opts) do
if compressible?(env.body) do
format = Keyword.get(opts || [], :format, "gzip")
env
|> Tesla.put_body(compress_body(env.body, format))
|> Tesla.put_headers([{"content-encoding", format}])
else
env
end
end
defp compress_body(body, "gzip"), do: :zlib.gzip(body)
defp compress_body(body, "deflate"), do: :zlib.zip(body)
@doc """
Decompress response.
It is used by `Tesla.Middleware.DecompressResponse`.
"""
def decompress({:ok, env}), do: {:ok, decompress(env)}
def decompress({:error, reason}), do: {:error, reason}
def decompress(env) do
codecs = compression_algorithms(Tesla.get_header(env, "content-encoding"))
{decompressed_body, unknown_codecs} = decompress_body(codecs, env.body, [])
env
|> put_decompressed_body(decompressed_body)
|> put_or_delete_content_encoding(unknown_codecs)
end
defp put_or_delete_content_encoding(env, []) do
Tesla.delete_header(env, "content-encoding")
end
defp put_or_delete_content_encoding(env, unknown_codecs) do
Tesla.put_header(env, "content-encoding", Enum.join(unknown_codecs, ", "))
end
defp decompress_body([gzip | rest], body, acc) when gzip in ["gzip", "x-gzip"] do
decompress_body(rest, :zlib.gunzip(body), acc)
end
defp decompress_body(["deflate" | rest], body, acc) do
decompress_body(rest, :zlib.unzip(body), acc)
end
defp decompress_body(["identity" | rest], body, acc) do
decompress_body(rest, body, acc)
end
defp decompress_body([codec | rest], body, acc) do
decompress_body(rest, body, [codec | acc])
end
defp decompress_body([], body, acc) do
{body, acc}
end
defp compression_algorithms(nil) do
[]
end
defp compression_algorithms(value) do
value
|> String.downcase()
|> String.split(",", trim: true)
|> Enum.map(&String.trim/1)
|> Enum.reverse()
end
defp put_decompressed_body(env, body) do
env
|> Tesla.put_body(body)
|> Tesla.delete_header("content-length")
end
end
defmodule Tesla.Middleware.CompressRequest do
@moduledoc """
Only compress request.
See `Tesla.Middleware.Compression` for options.
"""
@behaviour Tesla.Middleware
@impl Tesla.Middleware
def call(env, next, opts) do
env
|> Tesla.Middleware.Compression.compress(opts)
|> Tesla.run(next)
end
end
defmodule Tesla.Middleware.DecompressResponse do
@moduledoc """
Only decompress response.
See `Tesla.Middleware.Compression` for options.
"""
@behaviour Tesla.Middleware
@impl Tesla.Middleware
def call(env, next, _opts) do
env
|> Tesla.Middleware.Compression.add_accept_encoding()
|> Tesla.run(next)
|> Tesla.Middleware.Compression.decompress()
end
end