Skip to content

Commit

Permalink
Conditionally process :form bodies to handle nested params
Browse files Browse the repository at this point in the history
  • Loading branch information
vereis authored and edgurgel committed Mar 2, 2023
1 parent 596fa03 commit 0b96488
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
2 changes: 1 addition & 1 deletion lib/httpoison.ex
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ defmodule HTTPoison.Request do
headers = request.headers |> Enum.map(fn {k, v} -> "-H '#{k}: #{v}'" end) |> Enum.join(" ")

body =
case request.body do
case HTTPoison.Base.maybe_process_form(request.body) do
"" -> ""
{:file, filename} -> "-d @#{filename}"
{:form, form} -> form |> Enum.map(fn {k, v} -> "-F '#{k}=#{v}'" end) |> Enum.join(" ")
Expand Down
32 changes: 31 additions & 1 deletion lib/httpoison/base.ex
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,16 @@ defmodule HTTPoison.Base do
|> process_request_url()
|> HTTPoison.Base.build_request_url(params)

body =
request.body
|> process_request_body()
|> HTTPoison.Base.maybe_process_form()

request = %Request{
method: request.method,
url: url,
headers: process_request_headers(request.headers),
body: process_request_body(request.body),
body: body,
params: params,
options: options
}
Expand Down Expand Up @@ -985,4 +990,29 @@ defmodule HTTPoison.Base do
_ -> nil
end)
end

def maybe_process_form({:form, body}) do
{:form,
Enum.flat_map(body, fn
{k, [{_k, _v} | _rest] = v} -> flatten_nested_body(v, k)
{k, v} -> [{k, v}]
end)}
end

def maybe_process_form(body) do
body
end

defp flatten_nested_body(body, parent_key) do
flattened_body =
Enum.reduce(body, [], fn
{key, [{_key, _value} | _rest] = nested_key_values}, acc ->
flatten_nested_body(nested_key_values, "#{parent_key}[#{key}]") ++ acc

{key, value}, acc ->
[{"#{parent_key}[#{key}]", value} | acc]
end)

Enum.reverse(flattened_body)
end
end
23 changes: 23 additions & 0 deletions test/httpoison_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,29 @@ defmodule HTTPoisonTest do
)
end

test "post nested form data" do
assert_response(
HTTPoison.post(
"localhost:4002/post",
{:form, [not_nested: [1, 2], nested: [foo: "bar", again: [hello: "world"]]]},
%{"Content-type" => "application/x-www-form-urlencoded"}
),
fn %HTTPoison.Response{request: request} = response ->
assert {:form,
[{:not_nested, [1, 2]}, {"nested[foo]", "bar"}, {"nested[again][hello]", "world"}]} =
request.body

Regex.match?(~r/"not_nested".*\x01\x02/, response.body)
Regex.match?(~r/"nested\[foo\]".*"bar"/, response.body)
Regex.match?(~r/"nested\[again\]\[hello\]".*"world"/, response.body)

assert Request.to_curl(response.request) ==
{:ok,
"curl -X POST -H 'Content-type: application/x-www-form-urlencoded' -F 'not_nested=\x01\x02' -F 'nested[foo]=bar' -F 'nested[again][hello]=world' http://localhost:4002/post"}
end
)
end

test "put" do
assert_response(HTTPoison.put("localhost:4002/put", "test"), fn response ->
assert Request.to_curl(response.request) ==
Expand Down

0 comments on commit 0b96488

Please sign in to comment.