mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-15 04:30:25 +00:00
Add the 'int' constraint
This commit is contained in:
parent
a357c49d1b
commit
a5a69353f1
2 changed files with 59 additions and 10 deletions
|
@ -196,8 +196,9 @@ Constraints
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
After the matching has completed, the resulting bindings can be tested
|
After the matching has completed, the resulting bindings can be tested
|
||||||
against a set of constraints. The match will succeed only if they all
|
against a set of constraints. Constraints are only tested when the
|
||||||
succeed.
|
binding is defined. They run in the order you defined them. The match
|
||||||
|
will succeed only if they all succeed.
|
||||||
|
|
||||||
They are always given as a two or three elements tuple, where the first
|
They are always given as a two or three elements tuple, where the first
|
||||||
element is the name of the binding, the second element is the constraint's
|
element is the name of the binding, the second element is the constraint's
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
-export_type([bindings/0]).
|
-export_type([bindings/0]).
|
||||||
-export_type([tokens/0]).
|
-export_type([tokens/0]).
|
||||||
|
|
||||||
-type constraints() :: [].
|
-type constraints() :: [{atom(), int}].
|
||||||
-export_type([constraints/0]).
|
-export_type([constraints/0]).
|
||||||
|
|
||||||
-type route_match() :: binary() | string().
|
-type route_match() :: binary() | string().
|
||||||
|
@ -222,16 +222,22 @@ match([], _, _) ->
|
||||||
%% If the host is '_' then there can be no constraints.
|
%% If the host is '_' then there can be no constraints.
|
||||||
match([{'_', [], PathMatchs}|_Tail], _, Path) ->
|
match([{'_', [], PathMatchs}|_Tail], _, Path) ->
|
||||||
match_path(PathMatchs, undefined, Path, []);
|
match_path(PathMatchs, undefined, Path, []);
|
||||||
match([{HostMatch, _Constraints, PathMatchs}|Tail], Tokens, Path)
|
match([{HostMatch, Constraints, PathMatchs}|Tail], Tokens, Path)
|
||||||
when is_list(Tokens) ->
|
when is_list(Tokens) ->
|
||||||
case list_match(Tokens, HostMatch, []) of
|
case list_match(Tokens, HostMatch, []) of
|
||||||
false ->
|
false ->
|
||||||
match(Tail, Tokens, Path);
|
match(Tail, Tokens, Path);
|
||||||
{true, Bindings, undefined} ->
|
|
||||||
match_path(PathMatchs, undefined, Path, Bindings);
|
|
||||||
{true, Bindings, HostInfo} ->
|
{true, Bindings, HostInfo} ->
|
||||||
match_path(PathMatchs, lists:reverse(HostInfo),
|
HostInfo2 = case HostInfo of
|
||||||
Path, Bindings)
|
undefined -> undefined;
|
||||||
|
_ -> lists:reverse(HostInfo)
|
||||||
|
end,
|
||||||
|
case check_constraints(Constraints, Bindings) of
|
||||||
|
{ok, Bindings2} ->
|
||||||
|
match_path(PathMatchs, HostInfo2, Path, Bindings2);
|
||||||
|
nomatch ->
|
||||||
|
match(Tail, Tokens, Path)
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
match(Dispatch, Host, Path) ->
|
match(Dispatch, Host, Path) ->
|
||||||
match(Dispatch, split_host(Host), Path).
|
match(Dispatch, split_host(Host), Path).
|
||||||
|
@ -249,19 +255,50 @@ match_path([{'_', [], Handler, Opts}|_Tail], HostInfo, _, Bindings) ->
|
||||||
{ok, Handler, Opts, Bindings, HostInfo, undefined};
|
{ok, Handler, Opts, Bindings, HostInfo, undefined};
|
||||||
match_path([{<<"*">>, _Constraints, Handler, Opts}|_Tail], HostInfo, <<"*">>, Bindings) ->
|
match_path([{<<"*">>, _Constraints, Handler, Opts}|_Tail], HostInfo, <<"*">>, Bindings) ->
|
||||||
{ok, Handler, Opts, Bindings, HostInfo, undefined};
|
{ok, Handler, Opts, Bindings, HostInfo, undefined};
|
||||||
match_path([{PathMatch, _Constraints, Handler, Opts}|Tail], HostInfo, Tokens,
|
match_path([{PathMatch, Constraints, Handler, Opts}|Tail], HostInfo, Tokens,
|
||||||
Bindings) when is_list(Tokens) ->
|
Bindings) when is_list(Tokens) ->
|
||||||
case list_match(Tokens, PathMatch, []) of
|
case list_match(Tokens, PathMatch, []) of
|
||||||
false ->
|
false ->
|
||||||
match_path(Tail, HostInfo, Tokens, Bindings);
|
match_path(Tail, HostInfo, Tokens, Bindings);
|
||||||
{true, PathBinds, PathInfo} ->
|
{true, PathBinds, PathInfo} ->
|
||||||
{ok, Handler, Opts, Bindings ++ PathBinds, HostInfo, PathInfo}
|
case check_constraints(Constraints, PathBinds) of
|
||||||
|
{ok, PathBinds2} ->
|
||||||
|
{ok, Handler, Opts, Bindings ++ PathBinds2,
|
||||||
|
HostInfo, PathInfo};
|
||||||
|
nomatch ->
|
||||||
|
match_path(Tail, HostInfo, Tokens, Bindings)
|
||||||
|
end
|
||||||
end;
|
end;
|
||||||
match_path(_Dispatch, _HostInfo, badrequest, _Bindings) ->
|
match_path(_Dispatch, _HostInfo, badrequest, _Bindings) ->
|
||||||
{error, badrequest, path};
|
{error, badrequest, path};
|
||||||
match_path(Dispatch, HostInfo, Path, Bindings) ->
|
match_path(Dispatch, HostInfo, Path, Bindings) ->
|
||||||
match_path(Dispatch, HostInfo, split_path(Path), Bindings).
|
match_path(Dispatch, HostInfo, split_path(Path), Bindings).
|
||||||
|
|
||||||
|
check_constraints([], Bindings) ->
|
||||||
|
{ok, Bindings};
|
||||||
|
check_constraints([Constraint|Tail], Bindings) ->
|
||||||
|
Name = element(1, Constraint),
|
||||||
|
case lists:keyfind(Name, 1, Bindings) of
|
||||||
|
false ->
|
||||||
|
check_constraints(Tail, Bindings);
|
||||||
|
{_, Value} ->
|
||||||
|
case check_constraint(Constraint, Value) of
|
||||||
|
true ->
|
||||||
|
check_constraints(Tail, Bindings);
|
||||||
|
{true, Value2} ->
|
||||||
|
Bindings2 = lists:keyreplace(Name, 1, Bindings,
|
||||||
|
{Name, Value2}),
|
||||||
|
check_constraints(Tail, Bindings2);
|
||||||
|
false ->
|
||||||
|
nomatch
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
check_constraint({_, int}, Value) ->
|
||||||
|
try {true, list_to_integer(binary_to_list(Value))}
|
||||||
|
catch _:_ -> false
|
||||||
|
end.
|
||||||
|
|
||||||
%% @doc Split a hostname into a list of tokens.
|
%% @doc Split a hostname into a list of tokens.
|
||||||
-spec split_host(binary()) -> tokens().
|
-spec split_host(binary()) -> tokens().
|
||||||
split_host(Host) ->
|
split_host(Host) ->
|
||||||
|
@ -478,4 +515,15 @@ match_info_test_() ->
|
||||||
R = match(Dispatch, H, P)
|
R = match(Dispatch, H, P)
|
||||||
end} || {H, P, R} <- Tests].
|
end} || {H, P, R} <- Tests].
|
||||||
|
|
||||||
|
match_constraints_test() ->
|
||||||
|
Dispatch = [{'_', [],
|
||||||
|
[{[<<"path">>, value], [{value, int}], match, []}]}],
|
||||||
|
{ok, _, [], [{value, 123}], _, _} = match(Dispatch,
|
||||||
|
<<"ninenines.eu">>, <<"/path/123">>),
|
||||||
|
{ok, _, [], [{value, 123}], _, _} = match(Dispatch,
|
||||||
|
<<"ninenines.eu">>, <<"/path/123/">>),
|
||||||
|
{error, notfound, path} = match(Dispatch,
|
||||||
|
<<"ninenines.eu">>, <<"/path/NaN/">>),
|
||||||
|
ok.
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue