From 82cd22a88b3f87064d9f17e36652b104b709a679 Mon Sep 17 00:00:00 2001 From: Paul Fisher Date: Tue, 22 Dec 2015 12:19:28 -0600 Subject: Allow colon within path segments Allow `cowboy_router:compile` to handle colon characters within path segments, rather than exiting with `badarg`. This is allowed via RFC 7230 2.7 -> [RFC 3986 3.3](https://tools.ietf.org/html/rfc3986#section-3.3): ``` segment = *pchar segment-nz = 1*pchar segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) ; non-zero-length segment without any colon ":" pchar = unreserved / pct-encoded / sub-delims / ":" / "@" ``` --- src/cowboy_router.erl | 3 +-- test/http_SUITE.erl | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/cowboy_router.erl b/src/cowboy_router.erl index fb5c383..92ecf25 100644 --- a/src/cowboy_router.erl +++ b/src/cowboy_router.erl @@ -101,12 +101,11 @@ compile_rules(<< S, Rest/bits >>, S, Segments, Rules, <<>>) -> compile_rules(Rest, S, Segments, Rules, <<>>); compile_rules(<< S, Rest/bits >>, S, Segments, Rules, Acc) -> compile_rules(Rest, S, [Acc|Segments], Rules, <<>>); +%% Colon on path segment start is special, otherwise allow. compile_rules(<< $:, Rest/bits >>, S, Segments, Rules, <<>>) -> {NameBin, Rest2} = compile_binding(Rest, S, <<>>), Name = binary_to_atom(NameBin, utf8), compile_rules(Rest2, S, Segments, Rules, Name); -compile_rules(<< $:, _/bits >>, _, _, _, _) -> - error(badarg); compile_rules(<< $[, $., $., $., $], Rest/bits >>, S, Segments, Rules, Acc) when Acc =:= <<>> -> compile_rules(Rest, S, ['...'|Segments], Rules, Acc); diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index 52ef86b..d77b760 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -35,12 +35,13 @@ all() -> {group, http_compress}, {group, https_compress}, {group, parse_host}, - {group, set_env} + {group, set_env}, + {group, router_compile} ]. groups() -> Tests = ct_helper:all(?MODULE) -- [ - parse_host, set_env_dispatch + parse_host, set_env_dispatch, path_allow_colon ], [ {http, [], Tests}, %% @todo parallel @@ -52,6 +53,9 @@ groups() -> ]}, {set_env, [], [ set_env_dispatch + ]}, + {router_compile, [], [ + path_allow_colon ]} ]. @@ -85,8 +89,12 @@ init_per_group(set_env, Config) -> env => #{dispatch => []} }), Port = ranch:get_port(set_env), - [{type, tcp}, {protocol, http}, {port, Port}, {opts, []}|Config]. + [{type, tcp}, {protocol, http}, {port, Port}, {opts, []}|Config]; +init_per_group(router_compile, Config) -> + Config. +end_per_group(router_compile, _) -> + ok; end_per_group(Name, _) -> ok = cowboy:stop_listener(Name). @@ -588,6 +596,10 @@ set_env_dispatch(Config) -> {response, nofin, 200, _} = gun:await(ConnPid2, Ref2), ok. +path_allow_colon(_Config) -> + cowboy_router:compile([{'_', [{"/foo/bar:blah", http_handler, []}]}]), + ok. + set_resp_body(Config) -> ConnPid = gun_open(Config), Ref = gun:get(ConnPid, "/set_resp/body"), -- cgit v1.2.3