Skip to content

Commit

Permalink
decode_body: Support application/zstd and .zst (#381)
Browse files Browse the repository at this point in the history
  • Loading branch information
dlindenkreuz committed Jul 4, 2024
1 parent 15cf6df commit a45e402
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 2 deletions.
17 changes: 17 additions & 0 deletions lib/req/steps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,7 @@ defmodule Req.Steps do
| `tar`, `tgz` | `:erl_tar.extract/2` |
| `zip` | `:zip.unzip/2` |
| `gzip` | `:zlib.gunzip/1` |
| `zst` | `:ezstd.decompress/1` (if [ezstd] is installed) |
| `csv` | `NimbleCSV.RFC4180.parse_string/2` (if [nimble_csv] is installed) |
The format is determined based on the `content-type` header of the response. For example,
Expand Down Expand Up @@ -1498,6 +1499,7 @@ defmodule Req.Steps do
true
[nimble_csv]: https://hex.pm/packages/nimble_csv
[ezstd]: https://hex.pm/packages/ezstd
"""
@doc step: :response
def decode_body(request_response)
Expand Down Expand Up @@ -1569,6 +1571,21 @@ defmodule Req.Steps do
{request, update_in(response.body, &:zlib.gunzip/1)}
end

defp decode_body({request, response}, "zst") do
if ezstd_loaded?() do
case :ezstd.decompress(response.body) do
decompressed when is_binary(decompressed) ->
{request, put_in(response.body, decompressed)}

{:error, reason} ->
err = %RuntimeError{message: "Could not decompress Zstandard data: #{inspect(reason)}"}
{request, err}
end
else
{request, response}
end
end

defp decode_body({request, response}, "csv") do
if nimble_csv_loaded?() do
options = [skip_headers: false]
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ defmodule Req.MixProject do
defp deps do
[
{:finch, "~> 0.17", finch_opts()},
{:mime, "~> 1.6 or ~> 2.0"},
{:mime, "~> 2.0.6 or ~> 2.1"},
{:jason, "~> 1.0"},
{:nimble_csv, "~> 1.0", optional: true},
{:plug, "~> 1.0", [optional: true] ++ plug_opts()},
Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
"mint": {:hex, :mint, "1.6.0", "88a4f91cd690508a04ff1c3e28952f322528934be541844d54e0ceb765f01d5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "3c5ae85d90a5aca0a49c0d8b67360bbe407f3b54f1030a111047ff988e8fefaa"},
"nimble_csv": {:hex, :nimble_csv, "1.2.0", "4e26385d260c61eba9d4412c71cea34421f296d5353f914afe3f2e71cce97722", [:mix], [], "hexpm", "d0628117fcc2148178b034044c55359b26966c6eaa8e2ce15777be3bbc91b12a"},
"nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
Expand Down
34 changes: 34 additions & 0 deletions test/req/steps_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,40 @@ defmodule Req.StepsTest do
end
end

test "zstd (content-type)" do
plug = fn conn ->
conn
|> Plug.Conn.put_resp_content_type("application/zstd", nil)
|> Plug.Conn.send_resp(200, :ezstd.compress("foo"))
end

assert Req.get!(plug: plug).body == "foo"
end

test "zstd (path)" do
plug = fn conn ->
conn
|> Plug.Conn.put_resp_content_type("application/octet-stream", nil)
|> Plug.Conn.send_resp(200, :ezstd.compress("foo"))
end

assert Req.get!(plug: plug, url: "/foo.zst").body == "foo"
end

test "zstd invalid" do
plug = fn conn ->
conn
|> Plug.Conn.put_resp_content_type("application/zstd", nil)
|> Plug.Conn.send_resp(200, "bad")
end

assert {:error, e} = Req.get(plug: plug)
assert %RuntimeError{} = e

assert Exception.message(e) ==
"Could not decompress Zstandard data: \"failed to decompress: ZSTD_CONTENTSIZE_ERROR\""
end

test "csv" do
csv = [
["x", "y"],
Expand Down

0 comments on commit a45e402

Please sign in to comment.