diff options
-rw-r--r-- | guide/routing.md | 3 | ||||
-rw-r--r-- | src/cowboy_router.erl | 15 |
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. |