diff --git a/src/mochiweb_request.erl b/src/mochiweb_request.erl index 39890ce0..4fd7d687 100644 --- a/src/mochiweb_request.erl +++ b/src/mochiweb_request.erl @@ -136,8 +136,9 @@ get(path, {?MODULE, [_Socket, _Opts, _Method, RawPath, _Version, _Headers]}) -> undefined -> {Path0, _, _} = mochiweb_util:urlsplit_path(RawPath), Path = mochiweb_util:unquote(Path0), - put(?SAVE_PATH, Path), - Path; + Path_n = mochiweb_util:normalize_path(Path), + put(?SAVE_PATH, Path_n), + Path_n; Cached -> Cached end; diff --git a/src/mochiweb_util.erl b/src/mochiweb_util.erl index c6067674..22ae8f4e 100644 --- a/src/mochiweb_util.erl +++ b/src/mochiweb_util.erl @@ -14,6 +14,7 @@ -export([safe_relative_path/1, partition/2]). -export([parse_qvalues/1, pick_accepted_encodings/3]). -export([make_io/1]). +-export([normalize_path/1]). -define(PERCENT, 37). % $\% -define(FULLSTOP, 46). % $\. @@ -586,6 +587,19 @@ make_io(Integer) when is_integer(Integer) -> make_io(Io) when is_list(Io); is_binary(Io) -> Io. +%% @spec normalize_path(string()) -> string() +%% @doc Remove duplicate slashes from an uri path ("//foo///bar////" becomes +%% "/foo/bar/"). +normalize_path(Path) -> + normalize_path(Path, []). + +normalize_path([], Acc) -> + lists:reverse(Acc); +normalize_path("/" ++ Path, "/" ++ _ = Acc) -> + normalize_path(Path, Acc); +normalize_path([C|Path], Acc) -> + normalize_path(Path, [C|Acc]). + %% %% Tests %% @@ -990,4 +1004,35 @@ pick_accepted_encodings_test() -> ), ok. +normalize_path_test() -> + "" = normalize_path(""), + "/" = normalize_path("/"), + "/" = normalize_path("//"), + "/" = normalize_path("///"), + "foo" = normalize_path("foo"), + "/foo" = normalize_path("/foo"), + "/foo" = normalize_path("//foo"), + "/foo" = normalize_path("///foo"), + "foo/" = normalize_path("foo/"), + "foo/" = normalize_path("foo//"), + "foo/" = normalize_path("foo///"), + "foo/bar" = normalize_path("foo/bar"), + "foo/bar" = normalize_path("foo//bar"), + "foo/bar" = normalize_path("foo///bar"), + "foo/bar" = normalize_path("foo////bar"), + "/foo/bar" = normalize_path("/foo/bar"), + "/foo/bar" = normalize_path("/foo////bar"), + "/foo/bar" = normalize_path("////foo/bar"), + "/foo/bar" = normalize_path("////foo///bar"), + "/foo/bar" = normalize_path("////foo////bar"), + "/foo/bar/" = normalize_path("/foo/bar/"), + "/foo/bar/" = normalize_path("////foo/bar/"), + "/foo/bar/" = normalize_path("/foo////bar/"), + "/foo/bar/" = normalize_path("/foo/bar////"), + "/foo/bar/" = normalize_path("///foo////bar/"), + "/foo/bar/" = normalize_path("////foo/bar////"), + "/foo/bar/" = normalize_path("/foo///bar////"), + "/foo/bar/" = normalize_path("////foo///bar////"), + ok. + -endif. diff --git a/test/mochiweb_tests.erl b/test/mochiweb_tests.erl index 0b558ac5..22e5b26a 100644 --- a/test/mochiweb_tests.erl +++ b/test/mochiweb_tests.erl @@ -6,7 +6,7 @@ with_server(Transport, ServerFun, ClientFun) -> mochiweb_test_util:with_server(Transport, ServerFun, ClientFun). request_test() -> - R = mochiweb_request:new(z, z, "/foo/bar/baz%20wibble+quux?qs=2", z, []), + R = mochiweb_request:new(z, z, "//foo///bar/baz%20wibble+quux?qs=2", z, []), "/foo/bar/baz wibble quux" = R:get(path), ok.