Skip to content

Commit 6d292f5

Browse files
committed
Added route matching function
1 parent 9dbd022 commit 6d292f5

File tree

2 files changed

+54
-9
lines changed

2 files changed

+54
-9
lines changed

lib/bypass/instance.ex

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ defmodule Bypass.Instance do
22
use GenServer, restart: :transient
33

44
import Bypass.Utils
5+
import Plug.Router.Utils, only: [build_path_match: 1]
56

67
def start_link(opts \\ []) do
78
GenServer.start_link(__MODULE__, [opts])
@@ -139,6 +140,7 @@ defmodule Bypass.Instance do
139140
route,
140141
new_route(
141142
fun,
143+
path,
142144
case expect do
143145
:expect -> :once_or_more
144146
:expect_once -> :once
@@ -285,18 +287,51 @@ defmodule Bypass.Instance do
285287
end
286288

287289
defp route_info(method, path, %{expectations: expectations} = _state) do
288-
route =
289-
case Map.get(expectations, {method, path}, :no_expectations) do
290-
:no_expectations ->
291-
{:any, :any}
290+
segments = build_path_match(path) |> elem(1)
292291

293-
_ ->
294-
{method, path}
295-
end
292+
route =
293+
expectations
294+
|> Enum.reduce_while(
295+
{:any, :any, %{}},
296+
fn
297+
{{^method, path_pattern}, %{path_parts: path_parts}}, acc ->
298+
case match_route(segments, path_parts) do
299+
{true, params} -> {:halt, {method, path_pattern, params}}
300+
{false, _} -> {:cont, acc}
301+
end
302+
303+
_, acc ->
304+
{:cont, acc}
305+
end
306+
)
296307

297308
{route, Map.get(expectations, route)}
298309
end
299310

311+
defp match_route(path, route) do
312+
case length(path) == length(route) do
313+
true ->
314+
path
315+
|> Enum.zip(route)
316+
|> Enum.reduce_while(
317+
{true, %{}},
318+
fn
319+
{value, {param, _, _}}, {_, params} ->
320+
{:cont, {true, Map.put(params, Atom.to_string(param), value)}}
321+
322+
{segment, segment}, acc ->
323+
{:cont, acc}
324+
325+
_, _ ->
326+
{:halt, {false, nil}}
327+
end
328+
)
329+
330+
false ->
331+
{false, nil}
332+
end
333+
end
334+
300335
defp do_up(port, ref) do
301336
plug_opts = [self()]
302337
{:ok, socket} = :ranch_tcp.listen(so_reuseport() ++ [ip: listen_ip(), port: port])
@@ -353,16 +388,23 @@ defmodule Bypass.Instance do
353388
|> length
354389
end
355390

356-
defp new_route(fun, expected) do
391+
defp new_route(fun, path_parts, expected) when is_list(path_parts) do
357392
%{
358393
fun: fun,
359394
expected: expected,
395+
path_parts: path_parts,
360396
retained_plugs: %{},
361397
results: [],
362398
request_count: 0
363399
}
364400
end
365401

402+
defp new_route(fun, :any, expected),
403+
do: new_route(fun, [], expected)
404+
405+
defp new_route(fun, path, expected),
406+
do: new_route(fun, build_path_match(path) |> elem(1), expected)
407+
366408
defp cowboy_opts(port, ref, socket) do
367409
case Application.spec(:plug_cowboy, :vsn) do
368410
'1.' ++ _ -> [ref: ref, acceptors: 5, port: port, socket: socket]

lib/bypass/plug.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ defmodule Bypass.Plug do
22
def init([pid]), do: pid
33

44
def call(%{method: method, request_path: request_path} = conn, pid) do
5-
route = Bypass.Instance.call(pid, {:get_route, method, request_path})
5+
{method, path, path_params} = Bypass.Instance.call(pid, {:get_route, method, request_path})
6+
route = {method, path}
67
ref = make_ref()
78

9+
conn = Plug.Conn.fetch_query_params(%{conn | params: path_params})
10+
811
case Bypass.Instance.call(pid, {:get_expect_fun, route}) do
912
fun when is_function(fun, 1) ->
1013
retain_current_plug(pid, route, ref)

0 commit comments

Comments
 (0)