aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--guide/routing.md3
-rw-r--r--src/cowboy_router.erl15
2 files changed, 15 insertions, 3 deletions
diff --git a/guide/routing.md b/guide/routing.md
index 659b27d..9d5c5af 100644
--- a/guide/routing.md
+++ b/guide/routing.md
@@ -207,7 +207,7 @@ name, and the optional third element is the constraint's arguments.
The following constraints are currently defined:
* {Name, int}
- * {Name, function, (fun(Value) -> true | {true, NewValue} | false)}
+ * {Name, function, fun ((Value) -> true | {true, NewValue} | false)}
The `int` constraint will check if the binding is a binary string
representing an integer, and if it is, will convert the value to integer.
@@ -215,6 +215,7 @@ representing an integer, and if it is, will convert the value to integer.
The `function` constraint will pass the binding value to a user specified
function that receives the binary value as its only argument and must
return whether it fulfills the constraint, optionally modifying the value.
+The value thus returned can be of any type.
Note that constraint functions SHOULD be pure and MUST NOT crash.
diff --git a/src/cowboy_router.erl b/src/cowboy_router.erl
index 7096bd3..f2d1127 100644
--- a/src/cowboy_router.erl
+++ b/src/cowboy_router.erl
@@ -33,7 +33,8 @@
-export_type([bindings/0]).
-export_type([tokens/0]).
--type constraints() :: [{atom(), int}].
+-type constraints() :: [{atom(), int}
+ | {atom(), function, fun ((binary()) -> true | {true, any()} | false)}].
-export_type([constraints/0]).
-type route_match() :: binary() | string().
@@ -297,7 +298,9 @@ check_constraints([Constraint|Tail], Bindings) ->
check_constraint({_, int}, Value) ->
try {true, list_to_integer(binary_to_list(Value))}
catch _:_ -> false
- end.
+ end;
+check_constraint({_, function, Fun}, Value) ->
+ Fun(Value).
%% @doc Split a hostname into a list of tokens.
-spec split_host(binary()) -> tokens().
@@ -524,6 +527,14 @@ match_constraints_test() ->
<<"ninenines.eu">>, <<"/path/123/">>),
{error, notfound, path} = match(Dispatch,
<<"ninenines.eu">>, <<"/path/NaN/">>),
+ Dispatch2 = [{'_', [],
+ [{[<<"path">>, username], [{username, function,
+ fun(Value) -> Value =:= cowboy_bstr:to_lower(Value) end}],
+ match, []}]}],
+ {ok, _, [], [{username, <<"essen">>}], _, _} = match(Dispatch2,
+ <<"ninenines.eu">>, <<"/path/essen">>),
+ {error, notfound, path} = match(Dispatch2,
+ <<"ninenines.eu">>, <<"/path/ESSEN">>),
ok.
-endif.