Skip to content

Commit 464cab0

Browse files
authored
Merge pull request #101 from josevalim/jv-latest-cowboy
Support latest Cowboy
2 parents 350b87e + 50e9ee6 commit 464cab0

File tree

6 files changed

+89
-94
lines changed

6 files changed

+89
-94
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ elixir:
44
- 1.9
55
- 1.8
66
- 1.7
7-
- 1.6
87
otp_release:
98
- 20.0
109
- 21.0

lib/bypass/instance.ex

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ defmodule Bypass.Instance do
4141
callers_awaiting_down: [],
4242
callers_awaiting_exit: [],
4343
pass: false,
44-
unknown_route_error: nil
44+
unknown_route_error: nil,
45+
monitors: %{}
4546
}
4647

4748
{:ok, state}
@@ -51,32 +52,24 @@ defmodule Bypass.Instance do
5152
end
5253
end
5354

54-
def handle_call(request, from, state) do
55-
debug_log([inspect(self()), " called ", inspect(request), " with state ", inspect(state)])
56-
do_handle_call(request, from, state)
57-
end
55+
def handle_info({:DOWN, ref, _, _, reason}, state) do
56+
case pop_in(state.monitors[ref]) do
57+
{nil, state} ->
58+
{:noreply, state}
5859

59-
def handle_cast({:retain_plug_process, {method, path} = route, ref, caller_pid}, state) do
60-
debug_log([
61-
inspect(self()),
62-
" retain_plug_process ",
63-
inspect(caller_pid),
64-
", retained_plugs: ",
65-
inspect(
66-
Map.get(state.expectations, route)
67-
|> Map.get(:retained_plugs)
68-
|> Map.values()
69-
)
70-
])
60+
{route, state} ->
61+
result = {:exit, {:exit, reason, []}}
62+
{:noreply, route |> put_result(ref, result, state) |> dispatch_awaiting_callers()}
63+
end
64+
end
7165

72-
updated_state =
73-
update_in(state[:expectations][route][:retained_plugs], fn plugs ->
74-
Map.update(plugs, ref, caller_pid, fn _ ->
75-
raise "plug already installed for #{method} #{path}"
76-
end)
77-
end)
66+
def handle_cast({:put_expect_result, route, ref, result}, state) do
67+
{:noreply, route |> put_result(ref, result, state) |> dispatch_awaiting_callers()}
68+
end
7869

79-
{:noreply, updated_state}
70+
def handle_call(request, from, state) do
71+
debug_log([inspect(self()), " called ", inspect(request), " with state ", inspect(state)])
72+
do_handle_call(request, from, state)
8073
end
8174

8275
defp do_handle_call(:port, _, %{port: port} = state) do
@@ -177,7 +170,7 @@ defmodule Bypass.Instance do
177170

178171
defp do_handle_call(
179172
{:get_expect_fun, route},
180-
_from,
173+
from,
181174
%{expectations: expectations} = state
182175
) do
183176
case Map.get(expectations, route) do
@@ -188,18 +181,12 @@ defmodule Bypass.Instance do
188181
{:reply, {:error, :unexpected_request, route}, state}
189182

190183
route_expectations ->
191-
{:reply, route_expectations.fun, increase_route_count(state, route)}
184+
state = increase_route_count(state, route)
185+
{ref, state} = retain_plug_process(route, from, state)
186+
{:reply, {:ok, ref, route_expectations.fun}, state}
192187
end
193188
end
194189

195-
defp do_handle_call({:put_expect_result, route, ref, result}, _from, state) do
196-
updated_state =
197-
put_result(route, ref, result, state)
198-
|> dispatch_awaiting_callers()
199-
200-
{:reply, :ok, updated_state}
201-
end
202-
203190
defp do_handle_call(:on_exit, from, %{callers_awaiting_exit: callers} = state) do
204191
if retained_plugs_count(state) > 0 do
205192
{:noreply, %{state | callers_awaiting_exit: [from | callers]}}
@@ -239,25 +226,25 @@ defmodule Bypass.Instance do
239226
end
240227

241228
defp put_result(route, ref, result, state) do
242-
case get_in(state, [:expectations, route]) do
243-
nil ->
244-
Map.put(state, :unknown_route_error, result)
229+
if state.expectations[route] do
230+
{_, state} = pop_in(state.monitors[ref])
245231

246-
_ ->
247-
update_in(state[:expectations][route], fn route_expectations ->
248-
plugs = Map.fetch!(route_expectations, :retained_plugs)
232+
update_in(state.expectations[route], fn route_expectations ->
233+
plugs = route_expectations.retained_plugs
249234

250-
Map.merge(route_expectations, %{
251-
retained_plugs: Map.delete(plugs, ref),
252-
results: [result | Map.fetch!(route_expectations, :results)]
253-
})
254-
end)
235+
Map.merge(route_expectations, %{
236+
retained_plugs: Map.delete(plugs, ref),
237+
results: [result | Map.fetch!(route_expectations, :results)]
238+
})
239+
end)
240+
else
241+
Map.put(state, :unknown_route_error, result)
255242
end
256243
end
257244

258245
defp increase_route_count(state, route) do
259246
update_in(
260-
state[:expectations][route],
247+
state.expectations[route],
261248
fn route_expectations -> Map.update(route_expectations, :request_count, 1, &(&1 + 1)) end
262249
)
263250
end
@@ -351,6 +338,31 @@ defmodule Bypass.Instance do
351338
end
352339
end
353340

341+
defp retain_plug_process({method, path} = route, {caller_pid, _}, state) do
342+
debug_log([
343+
inspect(self()),
344+
" retain_plug_process ",
345+
inspect(caller_pid),
346+
", retained_plugs: ",
347+
inspect(
348+
Map.get(state.expectations, route)
349+
|> Map.get(:retained_plugs)
350+
|> Map.values()
351+
)
352+
])
353+
354+
ref = Process.monitor(caller_pid)
355+
356+
state =
357+
update_in(state.expectations[route][:retained_plugs], fn plugs ->
358+
Map.update(plugs, ref, caller_pid, fn _ ->
359+
raise "plug already installed for #{method} #{path}"
360+
end)
361+
end)
362+
363+
{ref, put_in(state.monitors[ref], route)}
364+
end
365+
354366
defp dispatch_awaiting_callers(
355367
%{
356368
callers_awaiting_down: down_callers,

lib/bypass/plug.ex

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,10 @@ defmodule Bypass.Plug do
66
def call(%{method: method, request_path: request_path} = conn, pid) do
77
{method, path, path_params} = Bypass.Instance.call(pid, {:get_route, method, request_path})
88
route = {method, path}
9-
ref = make_ref()
10-
119
conn = Plug.Conn.fetch_query_params(%{conn | params: path_params})
1210

1311
case Bypass.Instance.call(pid, {:get_expect_fun, route}) do
14-
fun when is_function(fun, 1) ->
15-
retain_current_plug(pid, route, ref)
16-
12+
{:ok, ref, fun} ->
1713
try do
1814
fun.(conn)
1915
else
@@ -22,28 +18,18 @@ defmodule Bypass.Plug do
2218
conn
2319
catch
2420
class, reason ->
25-
stacktrace = unquote do
26-
if Version.match?(System.version(), ">= 1.7.0") do
27-
quote do: __STACKTRACE__
28-
else
29-
quote do: System.stacktrace()
30-
end
31-
end
21+
stacktrace = __STACKTRACE__
3222
put_result(pid, route, ref, {:exit, {class, reason, stacktrace}})
3323
:erlang.raise(class, reason, stacktrace)
3424
end
3525

3626
{:error, error, route} ->
37-
put_result(pid, route, ref, {:error, error, route})
38-
raise "Route error"
27+
put_result(pid, route, make_ref(), {:error, error, route})
28+
raise "route error"
3929
end
4030
end
4131

42-
defp retain_current_plug(pid, route, ref) do
43-
Bypass.Instance.cast(pid, {:retain_plug_process, route, ref, self()})
44-
end
45-
4632
defp put_result(pid, route, ref, result) do
47-
Bypass.Instance.call(pid, {:put_expect_result, route, ref, result})
33+
Bypass.Instance.cast(pid, {:put_expect_result, route, ref, result})
4834
end
4935
end

mix.exs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule Bypass.Mixfile do
88
[
99
app: :bypass,
1010
version: @version,
11-
elixir: "~> 1.6",
11+
elixir: "~> 1.7",
1212
description: description(),
1313
package: package(),
1414
deps: deps(),
@@ -18,7 +18,7 @@ defmodule Bypass.Mixfile do
1818

1919
def application do
2020
[
21-
applications: [:logger, :ranch, :cowboy, :plug, :plug_cowboy],
21+
extra_applications: [:logger],
2222
mod: {Bypass.Application, []},
2323
env: env()
2424
]
@@ -28,8 +28,7 @@ defmodule Bypass.Mixfile do
2828
[
2929
{:plug_cowboy, "~> 1.0 or ~> 2.0"},
3030
{:plug, "~> 1.7"},
31-
{:cowlib, "~> 1.0.1"},
32-
{:ranch, "~> 1.3.2"},
31+
{:ranch, "~> 1.3"},
3332
{:ex_doc, "> 0.0.0", only: :dev},
3433
{:espec, "~> 1.6", only: [:dev, :test]},
3534
{:mint, "~> 1.1", only: :test}

mix.lock

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
%{
2-
"cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "f4763bbe08233eceed6f24bc4fcc8d71c17cfeafa6439157c57349aa1bb4f17c"},
3-
"cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm", "db622da03aa039e6366ab953e31186cc8190d32905e33788a1acb22744e6abd2"},
2+
"cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e5580029080f3f1ad17436fb97b0d5ed2ed4e4815a96bac36b5a992e20f58db6"},
3+
"cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm", "1e1a3d176d52daebbecbbcdfd27c27726076567905c2a9d7398c54da9d225761"},
44
"earmark": {:hex, :earmark, "1.3.0", "17f0c38eaafb4800f746b457313af4b2442a8c2405b49c645768680f900be603", [:mix], [], "hexpm", "f8b8820099caf0d5e72ae6482d2b0da96f213cbbe2b5b2191a37966e119eaa27"},
5+
"earmark_parser": {:hex, :earmark_parser, "1.4.10", "6603d7a603b9c18d3d20db69921527f82ef09990885ed7525003c7fe7dc86c56", [:mix], [], "hexpm", "8e2d5370b732385db2c9b22215c3f59c84ac7dda7ed7e544d7c459496ae519c0"},
56
"espec": {:hex, :espec, "1.6.3", "d9355788e508b82743a1b1b9aa5ac64ba37b0547c6210328d909e8a6eb56d42e", [:mix], [{:meck, "0.8.12", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "235ef9931fc6ae8066272b77dc11c462e72af0aa50c6023643acd22b09326d21"},
6-
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "dc87f778d8260da0189a622f62790f6202af72f2f3dee6e78d91a18dd2fcd137"},
7+
"ex_doc": {:hex, :ex_doc, "0.22.2", "03a2a58bdd2ba0d83d004507c4ee113b9c521956938298eba16e55cc4aba4a6c", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "cf60e1b3e2efe317095b6bb79651f83a2c1b3edcb4d319c421d7fcda8b3aff26"},
78
"gun": {:git, "https://github.com/PSPDFKit-labs/gun.git", "0462585ec7b0bcb2ca4b8b91e6d2624a45324b6e", []},
8-
"makeup": {:hex, :makeup, "0.5.5", "9e08dfc45280c5684d771ad58159f718a7b5788596099bdfb0284597d368a882", [:mix], [{:nimble_parsec, "~> 0.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d7152ff93f2eac07905f510dfa03397134345ba4673a00fbf7119bab98632940"},
9-
"makeup_elixir": {:hex, :makeup_elixir, "0.10.0", "0f09c2ddf352887a956d84f8f7e702111122ca32fbbc84c2f0569b8b65cbf7fa", [:mix], [{:makeup, "~> 0.5.5", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "4a36dd2d0d5c5f98d95b3f410d7071cd661d5af310472229dd0e92161f168a44"},
9+
"makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"},
10+
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
1011
"meck": {:hex, :meck, "0.8.12", "1f7b1a9f5d12c511848fec26bbefd09a21e1432eadb8982d9a8aceb9891a3cf2", [:rebar3], [], "hexpm", "7a6ab35a42e6c846636e8ecd6fdf2cc2e3f09dbee1abb15c1a7c705c10775787"},
11-
"mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm", "5e839994289d60326aa86020c4fbd9c6938af188ecddab2579f07b66cd665328"},
12+
"mime": {:hex, :mime, "1.4.0", "5066f14944b470286146047d2f73518cf5cca82f8e4815cf35d196b58cf07c47", [:mix], [], "hexpm", "75fa42c4228ea9a23f70f123c74ba7cece6a03b1fd474fe13f6a7a85c6ea4ff6"},
1213
"mint": {:hex, :mint, "1.1.0", "1fd0189edd9e3ffdbd7fcd8bc3835902b987a63ec6c4fd1aa8c2a56e2165f252", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bfd316c3789340b682d5679a8116bcf2112e332447bdc20c1d62909ee45f48d"},
13-
"nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm", "ebb595e19456a72786db6dcd370d320350cb624f0b6203fcc7e23161d49b0ffb"},
14-
"plug": {:hex, :plug, "1.7.0", "cd8c8de89bd9de55eba1c918bf0e7f319737e109b6014875104af025a623e16e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm", "e21e0ea7cbf87ecbc6ab6a9418db78fa1285dc12c8e0586f44dd6dfa842a190b"},
15-
"plug_cowboy": {:hex, :plug_cowboy, "1.0.0", "2e2a7d3409746d335f451218b8bb0858301c3de6d668c3052716c909936eb57a", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "01d201427a8a1f4483be2465a98b45f5e82263327507fe93404a61c51eb9e9a8"},
16-
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm", "73c1682f0e414cfb5d9b95c8e8cd6ffcfdae699e3b05e1db744e58b7be857759"},
17-
"ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm", "6e56493a862433fccc3aca3025c946d6720d8eedf6e3e6fb911952a7071c357f"},
14+
"nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
15+
"plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.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", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"},
16+
"plug_cowboy": {:hex, :plug_cowboy, "2.1.3", "38999a3e85e39f0e6bdfdf820761abac61edde1632cfebbacc445cdcb6ae1333", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "056f41f814dbb38ea44613e0f613b3b2b2f2c6afce64126e252837669eba84db"},
17+
"plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
18+
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
19+
"telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
1820
}

test/bypass_test.exs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,12 @@ defmodule BypassTest do
115115
bypass,
116116
fn _conn ->
117117
Bypass.pass(bypass)
118-
Process.exit(self(), :normal)
119-
assert false
118+
Process.exit(self(), :shutdown)
120119
end
121120
])
122121

123122
capture_log(fn ->
124-
assert {:error, _conn, %Mint.TransportError{reason: :closed}, _responses} =
123+
assert {:error, _conn, %Mint.TransportError{reason: :timeout}, _responses} =
125124
request(bypass.port)
126125
end)
127126
end
@@ -166,8 +165,9 @@ defmodule BypassTest do
166165
apply(Bypass, expect_fun, [
167166
bypass,
168167
fn conn ->
168+
Process.flag(:trap_exit, true)
169169
result = Plug.Conn.send_resp(conn, 200, "")
170-
:timer.sleep(200)
170+
Process.sleep(200)
171171
send(test_process, ref)
172172
result
173173
end
@@ -192,7 +192,7 @@ defmodule BypassTest do
192192
"POST",
193193
"/this",
194194
fn conn ->
195-
:timer.sleep(200)
195+
Process.sleep(100)
196196
Plug.Conn.send_resp(conn, 200, "")
197197
end
198198
)
@@ -202,7 +202,7 @@ defmodule BypassTest do
202202
"POST",
203203
"/that",
204204
fn conn ->
205-
:timer.sleep(200)
205+
Process.sleep(100)
206206
result = Plug.Conn.send_resp(conn, 200, "")
207207
send(test_process, ref)
208208
result
@@ -222,7 +222,7 @@ defmodule BypassTest do
222222
# Here we make sure that Bypass.down waits until the plug process finishes
223223
# its work before shutting down.
224224
refute_received ^ref
225-
:timer.sleep(200)
225+
Process.sleep(200)
226226
Bypass.down(bypass)
227227

228228
Enum.map(tasks, fn task ->
@@ -431,18 +431,15 @@ defmodule BypassTest do
431431
closed error and not a failed to connect error, when we test Bypass.down.
432432
"""
433433
def request(port, path \\ "/example_path", method \\ "POST") do
434-
with {:ok, conn} <- Mint.HTTP.connect(:http, "127.0.0.1", port),
434+
with {:ok, conn} <- Mint.HTTP.connect(:http, "127.0.0.1", port, mode: :passive),
435435
{:ok, conn, ref} <- Mint.HTTP.request(conn, method, path, [], "") do
436436
receive_responses(conn, ref, 100, [])
437437
end
438438
end
439439

440440
defp receive_responses(conn, ref, status, body) do
441-
receive do
442-
message ->
443-
with {:ok, conn, responses} <- Mint.HTTP.stream(conn, message) do
444-
receive_responses(responses, conn, ref, status, body)
445-
end
441+
with {:ok, conn, responses} <- Mint.HTTP.recv(conn, 0, 200) do
442+
receive_responses(responses, conn, ref, status, body)
446443
end
447444
end
448445

0 commit comments

Comments
 (0)