From c9f5603650db717efe24dbf4d266071331f4e2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Mon, 6 Jun 2016 17:35:48 +0200 Subject: Router: properly handle path segments The path segments . and .. are now removed according to the rules found in RFC3986. The path segments are now percent-decoded using the correct algorithm (the one in RFC3986 and not the "query string" one). --- src/cowboy_router.erl | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'src/cowboy_router.erl') diff --git a/src/cowboy_router.erl b/src/cowboy_router.erl index f07b307..f2f8fb4 100644 --- a/src/cowboy_router.erl +++ b/src/cowboy_router.erl @@ -322,9 +322,9 @@ split_path(Path, Acc) -> try case binary:match(Path, <<"/">>) of nomatch when Path =:= <<>> -> - lists:reverse([cow_qs:urldecode(S) || S <- Acc]); + remove_dot_segments(lists:reverse([cow_uri:urldecode(S) || S <- Acc]), []); nomatch -> - lists:reverse([cow_qs:urldecode(S) || S <- [Path|Acc]]); + remove_dot_segments(lists:reverse([cow_uri:urldecode(S) || S <- [Path|Acc]]), []); {Pos, _} -> << Segment:Pos/binary, _:8, Rest/bits >> = Path, split_path(Rest, [Segment|Acc]) @@ -334,6 +334,27 @@ split_path(Path, Acc) -> badrequest end. +remove_dot_segments([], Acc) -> + lists:reverse(Acc); +remove_dot_segments([<<".">>|Segments], Acc) -> + remove_dot_segments(Segments, Acc); +remove_dot_segments([<<"..">>|Segments], Acc=[]) -> + remove_dot_segments(Segments, Acc); +remove_dot_segments([<<"..">>|Segments], [_|Acc]) -> + remove_dot_segments(Segments, Acc); +remove_dot_segments([S|Segments], Acc) -> + remove_dot_segments(Segments, [S|Acc]). + +-ifdef(TEST). +remove_dot_segments_test_() -> + Tests = [ + {[<<"a">>, <<"b">>, <<"c">>, <<".">>, <<"..">>, <<"..">>, <<"g">>], [<<"a">>, <<"g">>]}, + {[<<"mid">>, <<"content=5">>, <<"..">>, <<"6">>], [<<"mid">>, <<"6">>]}, + {[<<"..">>, <<"a">>], [<<"a">>]} + ], + [fun() -> R = remove_dot_segments(S, []) end || {S, R} <- Tests]. +-endif. + -spec list_match(tokens(), dispatch_match(), bindings()) -> {true, bindings(), undefined | tokens()} | false. %% Atom '...' matches any trailing path, stop right now. -- cgit v1.2.3