diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | include/types.hrl | 4 | ||||
-rw-r--r-- | src/cowboy_dispatcher.erl | 70 | ||||
-rw-r--r-- | src/cowboy_http_protocol.erl | 4 |
4 files changed, 54 insertions, 28 deletions
@@ -49,8 +49,8 @@ Code speaks more than words: application:start(cowboy), Dispatch = [ - %% Host, Path, Handler, Opts - {'_', '_', my_handler, []} + %% {Host, list({Path, Handler, Opts})} + {'_', [{'_', my_handler, []}]} ], %% NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts cowboy_listener_sup:start_link(100, diff --git a/include/types.hrl b/include/types.hrl index faee24e..17882cc 100644 --- a/include/types.hrl +++ b/include/types.hrl @@ -28,8 +28,8 @@ -type path_tokens() :: list(string()). -type match() :: '_' | list(string() | '_' | atom()). --type dispatch_rules() :: {Host::match(), Path::match(), - Handler::module(), Opts::term()}. +-type dispatch_rules() :: {Host::match(), list({Path::match(), + Handler::module(), Opts::term()})}. -type dispatch() :: list(dispatch_rules()). -type http_method() :: 'OPTIONS' | 'GET' | 'HEAD' diff --git a/src/cowboy_dispatcher.erl b/src/cowboy_dispatcher.erl index 3e9a7e0..755a398 100644 --- a/src/cowboy_dispatcher.erl +++ b/src/cowboy_dispatcher.erl @@ -35,18 +35,34 @@ split_path(Path) -> end. -spec match(Host::path_tokens(), Path::path_tokens(), Dispatch::dispatch()) - -> {ok, Handler::module(), Opts::term(), Binds::bindings()} | {error, notfound}. + -> {ok, Handler::module(), Opts::term(), Binds::bindings()} + | {error, notfound, host} | {error, notfound, path}. match(_Host, _Path, []) -> - {error, notfound}; -match(_Host, _Path, [{'_', '_', Handler, Opts}|_Tail]) -> - {ok, Handler, Opts, []}; -match(Host, Path, [{HostMatch, PathMatch, Handler, Opts}|Tail]) -> + {error, notfound, host}; +match(_Host, Path, [{'_', PathMatchs}|_Tail]) -> + match_path(Path, PathMatchs, []); +match(Host, Path, [{HostMatch, PathMatchs}|Tail]) -> case try_match(host, Host, HostMatch) of - false -> match(Host, Path, Tail); - {true, HostBinds} -> case try_match(path, Path, PathMatch) of - false -> match(Host, Path, Tail); - {true, PathBinds} -> {ok, Handler, Opts, HostBinds ++ PathBinds} - end + false -> + match(Host, Path, Tail); + {true, HostBinds} -> + match_path(Path, PathMatchs, HostBinds) + end. + +-spec match_path(Path::path_tokens(), list({Path::match(), + Handler::module(), Opts::term()}), HostBinds::bindings()) + -> {ok, Handler::module(), Opts::term(), Binds::bindings()} + | {error, notfound, path}. +match_path(_Path, [], _HostBinds) -> + {error, notfound, path}; +match_path(_Path, [{'_', Handler, Opts}|_Tail], HostBinds) -> + {ok, Handler, Opts, HostBinds}; +match_path(Path, [{PathMatch, Handler, Opts}|Tail], HostBinds) -> + case try_match(path, Path, PathMatch) of + false -> + match_path(Path, Tail, HostBinds); + {true, PathBinds} -> + {ok, Handler, Opts, HostBinds ++ PathBinds} end. %% Internal. @@ -116,16 +132,24 @@ split_path_test_() -> match_test_() -> Dispatch = [ - {["www", '_', "dev-extend", "eu"], ["users", '_', "mails"], - match_any_subdomain_users, []}, - {["dev-extend", "eu"], ["users", id, "friends"], - match_extend_users_friends, []}, - {["dev-extend", var], ["threads", var], - match_duplicate_vars, [we, {expect, two}, var, here]}, - {["dev-extend", "eu"], '_', match_extend, []}, - {["erlang", ext], '_', match_erlang_ext, []}, - {'_', ["users", id, "friends"], match_users_friends, []}, - {'_', '_', match_any, []} + {["www", '_', "dev-extend", "eu"], [ + {["users", '_', "mails"], match_any_subdomain_users, []} + ]}, + {["dev-extend", "eu"], [ + {["users", id, "friends"], match_extend_users_friends, []}, + {'_', match_extend, []} + ]}, + {["dev-extend", var], [ + {["threads", var], match_duplicate_vars, + [we, {expect, two}, var, here]} + ]}, + {["erlang", ext], [ + {'_', match_erlang_ext, []} + ]}, + {'_', [ + {["users", id, "friends"], match_users_friends, []}, + {'_', match_any, []} + ]} ], %% {Host, Path, Result} Tests = [ @@ -135,16 +159,16 @@ match_test_() -> {["www", "dev-extend", "eu"], ["users", "42", "mails"], {ok, match_any, [], []}}, {["www", "any", "dev-extend", "eu"], ["not_users", "42", "mails"], - {ok, match_any, [], []}}, + {error, notfound, path}}, {["dev-extend", "eu"], [], {ok, match_extend, [], []}}, {["dev-extend", "eu"], ["users", "42", "friends"], {ok, match_extend_users_friends, [], [{id, "42"}]}}, {["erlang", "fr"], '_', {ok, match_erlang_ext, [], [{ext, "fr"}]}}, {["any"], ["users", "444", "friends"], {ok, match_users_friends, [], [{id, "444"}]}}, - {["dev-extend", "eu"], ["threads", "987"], + {["dev-extend", "fr"], ["threads", "987"], {ok, match_duplicate_vars, [we, {expect, two}, var, here], - [{var, "eu"}, {var, "987"}]}} + [{var, "fr"}, {var, "987"}]}} ], [{lists:flatten(io_lib:format("~p, ~p", [H, P])), fun() -> R = match(H, P, Dispatch) diff --git a/src/cowboy_http_protocol.erl b/src/cowboy_http_protocol.erl index 0ea2cd9..82cf733 100644 --- a/src/cowboy_http_protocol.erl +++ b/src/cowboy_http_protocol.erl @@ -99,7 +99,9 @@ header({http_header, _I, 'Host', _R, Value}, Req=#http_req{path=Path, wait_header(Req#http_req{host=Host, bindings=Binds, headers=[{'Host', Value2}|Req#http_req.headers]}, State#state{handler={Handler, Opts}}); - {error, notfound} -> + {error, notfound, host} -> + error_terminate(400, State); + {error, notfound, path} -> error_terminate(404, State) end; %% Ignore Host headers if we already have it. |