From 1e791e1e42f320e6fdeafb3dc56eae0075407ffd Mon Sep 17 00:00:00 2001 From: Kevin Schweikert Date: Sun, 26 Jan 2025 23:43:49 +0100 Subject: [PATCH] handle header list correctly --- lib/curl_req/curl.ex | 2 +- lib/curl_req/req.ex | 5 +++-- lib/curl_req/request.ex | 28 ++++++++++++++-------------- mix.exs | 1 + mix.lock | 2 ++ test/curl_req_test.exs | 20 ++++++++++---------- 6 files changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/curl_req/curl.ex b/lib/curl_req/curl.ex index 92f0892..7b13f11 100644 --- a/lib/curl_req/curl.ex +++ b/lib/curl_req/curl.ex @@ -288,7 +288,7 @@ defmodule CurlReq.Curl do headers = for {key, values} <- request.headers, reduce: [] do headers -> - [headers, header_flag(flag_style, [key, ": ", Enum.intersperse(values, "; ")])] + [headers, header_flag(flag_style, [key, ": ", Enum.intersperse(values, ", ")])] end headers = diff --git a/lib/curl_req/req.ex b/lib/curl_req/req.ex index 3db24f7..700d3dc 100644 --- a/lib/curl_req/req.ex +++ b/lib/curl_req/req.ex @@ -149,10 +149,11 @@ defmodule CurlReq.Req do cookies = request.cookies |> Enum.map(fn {key, val} -> - IO.iodata_to_binary([key, "=", val]) + "#{key}=#{val}" end) + |> Enum.join("; ") - req = if cookies != [], do: Req.Request.put_header(req, "cookie", cookies), else: req + req = if request.cookies != %{}, do: Req.Request.put_header(req, "cookie", cookies), else: req proxy = if request.proxy do diff --git a/lib/curl_req/request.ex b/lib/curl_req/request.ex index 38e68e3..b179c58 100644 --- a/lib/curl_req/request.ex +++ b/lib/curl_req/request.ex @@ -73,42 +73,42 @@ defmodule CurlReq.Request do @spec put_header(__MODULE__.t(), String.t(), String.t() | [String.t()]) :: __MODULE__.t() def put_header(%__MODULE__{} = request, key, val) when is_binary(val) do key = String.downcase(key) |> String.trim() - val = String.split(val, ";", trim: true) |> Enum.map(&String.trim/1) - put_header(request, key, val) + val = String.trim(val) + put_header(request, key, [val]) end def put_header(%__MODULE__{} = request, key, val) when is_list(val) do key = String.downcase(key) |> String.trim() case {key, val} do - {"authorization", ["Bearer " <> token | _]} -> + {"authorization", ["Bearer " <> token]} -> %{request | auth: {:bearer, token}} - {"authorization", ["Basic " <> userinfo | _]} -> + {"authorization", ["Basic " <> userinfo]} -> %{request | auth: {:basic, userinfo}} {"accept-encoding", [compression | _]} when compression in ["gzip", "br", "zstd"] -> put_compression(request, String.to_existing_atom(compression)) - {"content-type", ["application/json" | _]} -> + {"content-type", ["application/json" <> _]} -> %{request | encoding: :json} - {"content-type", ["application/vnd.api+json" | _]} -> + {"content-type", ["application/vnd.api+json" <> _]} -> %{request | encoding: :json} - {"content-type", ["application/x-www-form-urlencoded" | _]} -> + {"content-type", ["application/x-www-form-urlencoded" <> _]} -> %{request | encoding: :form} - {"user-agent", [user_agent | _]} -> + {"user-agent", [user_agent]} -> put_user_agent(request, user_agent) - {"cookie", cookies} -> - for cookie <- cookies, reduce: request do - request -> - [key, value] = String.split(cookie, "=") - put_cookie(request, key, value) - end + {"cookie", [cookie]} -> + cookie + |> Plug.Conn.Cookies.decode() + |> Enum.reduce(request, fn {key, val}, request -> + put_cookie(request, key, val) + end) {key, val} -> headers = Map.put(request.headers, key, val) diff --git a/mix.exs b/mix.exs index a7770ee..992951c 100644 --- a/mix.exs +++ b/mix.exs @@ -26,6 +26,7 @@ defmodule CurlReq.MixProject do defp deps do [ {:req, "~> 0.4.0 or ~> 0.5.0"}, + {:plug, "~> 1.16"}, {:jason, "~> 1.4"}, {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, {:blend, "~> 0.4.1", only: :dev} diff --git a/mix.lock b/mix.lock index 3c2ddd4..6d16ab8 100644 --- a/mix.lock +++ b/mix.lock @@ -13,6 +13,8 @@ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, + "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "req": {:hex, :req, "0.5.8", "50d8d65279d6e343a5e46980ac2a70e97136182950833a1968b371e753f6a662", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "d7fc5898a566477e174f26887821a3c5082b243885520ee4b45555f5d53f40ef"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, } diff --git a/test/curl_req_test.exs b/test/curl_req_test.exs index 1529806..aab1444 100644 --- a/test/curl_req_test.exs +++ b/test/curl_req_test.exs @@ -90,7 +90,7 @@ defmodule CurlReqTest do end test "parameterized header" do - assert ~s(curl --compressed -H "my-header: foo; bar=baz" -X GET https://example.com) == + assert ~s(curl --compressed -H "my-header: foo, bar=baz" -X GET https://example.com) == Req.new(url: "https://example.com", headers: %{"my-header" => ["foo", "bar=baz"]}) |> CurlReq.to_curl() end @@ -340,11 +340,11 @@ defmodule CurlReqTest do } end - test "header with parameter" do - assert ~CURL(curl -H "my-header: foo; bar=baz" https://example.com) == + test "multiple header" do + assert ~CURL(curl -H "my-header: foo, bar=baz" https://example.com) == %Req.Request{ url: URI.parse("https://example.com"), - headers: %{"my-header" => ["foo", "bar=baz"]} + headers: %{"my-header" => ["foo, bar=baz"]} } end @@ -352,12 +352,12 @@ defmodule CurlReqTest do request = ~CURL(curl --header 'Cookie: TealeafAkaSid=JA-JSAXRCLjKYhjV9IXTzYUbcV1Lnhqf; sapphire=1; visitorId=0184E4601D5A020183FFBB133 80347CE; GuestLocation=33196|25.660|-80.440|FL|US' -X GET https://example.com) - cookies = request.headers["cookie"] + [cookie] = request.headers["cookie"] - assert "TealeafAkaSid=JA-JSAXRCLjKYhjV9IXTzYUbcV1Lnhqf" in cookies - assert "sapphire=1" in cookies - assert "visitorId=0184E4601D5A020183FFBB133 80347CE" in cookies - assert "GuestLocation=33196|25.660|-80.440|FL|US" in cookies + assert String.contains?(cookie, "TealeafAkaSid=JA-JSAXRCLjKYhjV9IXTzYUbcV1Lnhqf") + assert String.contains?(cookie, "sapphire=1") + assert String.contains?(cookie, "visitorId=0184E4601D5A020183FFBB133 80347CE") + assert String.contains?(cookie, "GuestLocation=33196|25.660|-80.440|FL|US") end test "multiple headers with body" do @@ -417,7 +417,7 @@ defmodule CurlReqTest do assert ~CURL(http://example.com -b "name1=value1; name2=value2") == %Req.Request{ url: URI.parse("http://example.com"), - headers: %{"cookie" => ["name1=value1", "name2=value2"]} + headers: %{"cookie" => ["name1=value1; name2=value2"]} } end