aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_static.erl
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-09-07 12:18:16 +0200
committerLoïc Hoguin <[email protected]>2019-09-07 12:18:16 +0200
commit4427108b69fcd1e6a8233a217fa0e99d0564b714 (patch)
tree17f211a65ab85db82b312129782e8024c5639fa7 /src/cowboy_static.erl
parent36836594f83a9dfdb30472a792d7ff73b3b48e3e (diff)
downloadcowboy-4427108b69fcd1e6a8233a217fa0e99d0564b714.tar.gz
cowboy-4427108b69fcd1e6a8233a217fa0e99d0564b714.tar.bz2
cowboy-4427108b69fcd1e6a8233a217fa0e99d0564b714.zip
Improve the cowboy_static consistency across platforms
As a result we explictly reject path_info components that include a forward slash, backward slash or NUL character. This only applies to the [...] part of the path for dir/priv_dir configuration. Also improve the tests so that they work on Windows.
Diffstat (limited to 'src/cowboy_static.erl')
-rw-r--r--src/cowboy_static.erl70
1 files changed, 43 insertions, 27 deletions
diff --git a/src/cowboy_static.erl b/src/cowboy_static.erl
index d6ef45c..b0cf146 100644
--- a/src/cowboy_static.erl
+++ b/src/cowboy_static.erl
@@ -119,35 +119,51 @@ init_dir(Req, Path, HowToAccess, Extra) when is_list(Path) ->
init_dir(Req, list_to_binary(Path), HowToAccess, Extra);
init_dir(Req, Path, HowToAccess, Extra) ->
Dir = fullpath(filename:absname(Path)),
- PathInfo = cowboy_req:path_info(Req),
- Filepath = filename:join([Dir|escape_reserved(PathInfo)]),
- Len = byte_size(Dir),
- case fullpath(Filepath) of
- << Dir:Len/binary, $/, _/binary >> ->
- init_info(Req, Filepath, HowToAccess, Extra);
- << Dir:Len/binary >> ->
- init_info(Req, Filepath, HowToAccess, Extra);
- _ ->
- {cowboy_rest, Req, error}
+ case cowboy_req:path_info(Req) of
+ %% When dir/priv_dir are used and there is no path_info
+ %% this is a configuration error and we abort immediately.
+ undefined ->
+ {ok, cowboy_req:reply(500, Req), error};
+ PathInfo ->
+ case validate_reserved(PathInfo) of
+ error ->
+ {cowboy_rest, Req, error};
+ ok ->
+ Filepath = filename:join([Dir|PathInfo]),
+ Len = byte_size(Dir),
+ case fullpath(Filepath) of
+ << Dir:Len/binary, $/, _/binary >> ->
+ init_info(Req, Filepath, HowToAccess, Extra);
+ << Dir:Len/binary >> ->
+ init_info(Req, Filepath, HowToAccess, Extra);
+ _ ->
+ {cowboy_rest, Req, error}
+ end
+ end
end.
-escape_reserved([]) -> [];
-escape_reserved([P|Tail]) -> [escape_reserved(P, <<>>)|escape_reserved(Tail)].
+validate_reserved([]) ->
+ ok;
+validate_reserved([P|Tail]) ->
+ case validate_reserved1(P) of
+ ok -> validate_reserved(Tail);
+ error -> error
+ end.
-%% We escape the slash found in path segments because
-%% a segment corresponds to a directory entry, and
-%% therefore those slashes are expected to be part of
-%% the directory name.
-%%
-%% Note that on most systems the slash is prohibited
-%% and cannot appear in filenames, which means the
-%% requested file will end up being not found.
-escape_reserved(<<>>, Acc) ->
- Acc;
-escape_reserved(<< $/, Rest/bits >>, Acc) ->
- escape_reserved(Rest, << Acc/binary, $\\, $/ >>);
-escape_reserved(<< C, Rest/bits >>, Acc) ->
- escape_reserved(Rest, << Acc/binary, C >>).
+%% We always reject forward slash, backward slash and NUL as
+%% those have special meanings across the supported platforms.
+%% We could support the backward slash on some platforms but
+%% for the sake of consistency and simplicity we don't.
+validate_reserved1(<<>>) ->
+ ok;
+validate_reserved1(<<$/, _/bits>>) ->
+ error;
+validate_reserved1(<<$\\, _/bits>>) ->
+ error;
+validate_reserved1(<<0, _/bits>>) ->
+ error;
+validate_reserved1(<<_, Rest/bits>>) ->
+ validate_reserved1(Rest).
fullpath(Path) ->
fullpath(filename:split(Path), []).
@@ -290,7 +306,7 @@ bad_path_win32_check_test_() ->
-endif.
%% Reject requests that tried to access a file outside
-%% the target directory.
+%% the target directory, or used reserved characters.
-spec malformed_request(Req, State)
-> {boolean(), Req, State}.