diff --git a/CHANGELOG.md b/CHANGELOG.md index c6e9641..c818ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.1.11 (TBA) + +- Now uses `Plug.Conn.resp/3` instead of `Plug.Conn.send_resp/3` to prevent controlling process issue in Bandit + ## v0.1.10 (2023-02-22) - `:httpd` server adapter now can read request body diff --git a/lib/test_server.ex b/lib/test_server.ex index 0b3b8f8..3beed82 100644 --- a/lib/test_server.ex +++ b/lib/test_server.ex @@ -315,7 +315,7 @@ defmodule TestServer do end defp default_response_handler(conn) do - Conn.send_resp(conn, 200, to_string(Conn.get_http_protocol(conn))) + Conn.resp(conn, 200, to_string(Conn.get_http_protocol(conn))) end @doc """ diff --git a/mix.exs b/mix.exs index 3d8b901..0dfc6cd 100644 --- a/mix.exs +++ b/mix.exs @@ -45,6 +45,7 @@ defmodule TestServer.MixProject do {:ssl_verify_fun, ">= 0.0.0", only: [:test]}, {:credo, ">= 0.0.0", only: [:dev, :test]}, {:websockex, "~> 0.4.3", only: [:test]}, + {:mint, "~> 1.0", only: [:test]}, {:ex_doc, ">= 0.0.0", only: :dev, runtime: false} ] end diff --git a/mix.lock b/mix.lock index cea005f..fec2904 100644 --- a/mix.lock +++ b/mix.lock @@ -14,6 +14,7 @@ "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, + "mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"}, diff --git a/test/test_server_test.exs b/test/test_server_test.exs index 5ad8150..a2df643 100644 --- a/test/test_server_test.exs +++ b/test/test_server_test.exs @@ -80,7 +80,7 @@ defmodule TestServerTest do assert :ok = TestServer.add("/", to: fn conn -> assert conn.remote_ip == {0, 0, 0, 0, 0, 65_535, 32_512, 1} - Plug.Conn.send_resp(conn, 200, "OK") + Plug.Conn.resp(conn, 200, "OK") end) assert %{host: hostname} = URI.parse(TestServer.url("/")) @@ -188,7 +188,7 @@ defmodule TestServerTest do assert conn.remote_ip == {127, 0, 0, 1} assert conn.host == "custom-host" - Plug.Conn.send_resp(conn, 200, "OK") + Plug.Conn.resp(conn, 200, "OK") end) assert {:ok, _} = request(TestServer.url("/", host: "custom-host")) @@ -201,7 +201,7 @@ defmodule TestServerTest do assert conn.remote_ip == {0, 0, 0, 0, 0, 65_535, 32_512, 1} assert conn.host == "custom-host" - Plug.Conn.send_resp(conn, 200, "OK") + Plug.Conn.resp(conn, 200, "OK") end) assert {:ok, _} = request(TestServer.url("/", host: "custom-host")) @@ -321,7 +321,7 @@ defmodule TestServerTest do defmodule ToPlug do def init(opts), do: opts - def call(conn, _opts), do: Plug.Conn.send_resp(conn, 200, to_string(__MODULE__)) + def call(conn, _opts), do: Plug.Conn.resp(conn, 200, to_string(__MODULE__)) end assert :ok = TestServer.add("/", to: ToPlug) @@ -364,7 +364,7 @@ defmodule TestServerTest do test "with callback function" do assert :ok = TestServer.add("/", - to: fn conn -> Plug.Conn.send_resp(conn, 200, "function called") end + to: fn conn -> Plug.Conn.resp(conn, 200, "function called") end ) assert request(TestServer.url("/")) == {:ok, "function called"} @@ -388,6 +388,17 @@ defmodule TestServerTest do assert {:ok, _} = request(TestServer.url("/")) assert {:ok, _} = request(TestServer.url("/"), method: :post) end + + # `:httpd` has no HTTP/2 support + unless System.get_env("HTTP_SERVER") == "Httpd" do + test "with HTTP/2 client" do + {:ok, _instance} = TestServer.start(scheme: :https) + + assert :ok = TestServer.add("/") + + assert {:ok, "HTTP/2"} = http2_request(TestServer.url()) + end + end end describe "plug/2" do @@ -398,7 +409,7 @@ defmodule TestServerTest do %{conn | params: %{"plug" => "anonymous function", body: body}} end) - assert :ok = TestServer.add("/", to: &Plug.Conn.send_resp(&1, 200, URI.encode_query(&1.params))) + assert :ok = TestServer.add("/", to: &Plug.Conn.resp(&1, 200, URI.encode_query(&1.params))) assert {:ok, query} = request(TestServer.url("/")) assert URI.decode_query(query) == %{"plug" => "anonymous function", "body" => ""} @@ -412,7 +423,7 @@ defmodule TestServerTest do end assert :ok = TestServer.plug(ModulePlug) - assert :ok = TestServer.add("/", to: &Plug.Conn.send_resp(&1, 200, &1.params["plug"])) + assert :ok = TestServer.add("/", to: &Plug.Conn.resp(&1, 200, &1.params["plug"])) assert request(TestServer.url("/")) == {:ok, to_string(ModulePlug)} end @@ -495,7 +506,7 @@ defmodule TestServerTest do end end - # Prevent running httpd in CI + # Httpd adapter has no WebSocket support unless System.get_env("HTTP_SERVER") == "Httpd" do describe "websocket_init/3" do test "when instance not running" do @@ -766,4 +777,38 @@ defmodule TestServerTest do end end end + + # `:httpd` has no HTTP/2 support + unless System.get_env("HTTP_SERVER") == "Httpd" do + defp http2_request(url) do + opts = [transport_opts: [cacerts: TestServer.x509_suite().cacerts]] + uri = URI.parse(url) + scheme = String.to_atom(uri.scheme) + + {:ok, conn} = Mint.HTTP2.connect(scheme, uri.host, uri.port, opts) + {:ok, conn, _request_ref} = Mint.HTTP2.request(conn, "GET", uri.path || "/", _headers = [], _body = "") + + responses = stream_until_done(conn) + + {:data, _, body} = Enum.find(responses, & elem(&1, 0) == :data) + + {:ok, body} + end + + defp stream_until_done(conn, acc \\ []) do + next_message = + receive do + msg -> msg + end + + {:ok, conn, responses} = Mint.HTTP2.stream(conn, next_message) + + acc = acc ++ responses + + case Enum.any?(responses, & elem(&1, 0) == :done) do + true -> acc + false -> stream_until_done(conn, acc) + end + end + end end