mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 12:20:24 +00:00
Add directory redirection handling to cowboy_static
Directory accesses with no trailing slash will by default be redirected (301) to their canonical slashed version. New handler option 'directory_index' can be set to 'false' to disable, or to another status code such as 302. Directory accesses with a trailing slash can be redirected (301) to an index file. This is off by default. New handler option 'directory_index' can be set to 'true' or a status code such as 302, for the default "index.html", or to a binary string such as <<"index.php">>, or to a pair {Code, Filename}.
This commit is contained in:
parent
30ee75cea1
commit
5ced7c03c0
1 changed files with 68 additions and 1 deletions
|
@ -42,6 +42,10 @@
|
|||
-type state() :: {binary(), {direct | archive, #file_info{}}
|
||||
| {error, atom()}, extra()}.
|
||||
|
||||
-define(DEFAULT_INDEX, <<"index.html">>).
|
||||
-define(DEFAULT_REDIR, 301).
|
||||
|
||||
|
||||
%% Resolve the file that will be sent and get its file information.
|
||||
%% If the handler is configured to manage a directory, check that the
|
||||
%% requested file is inside the configured directory.
|
||||
|
@ -180,7 +184,70 @@ fullpath([Segment|Tail], Acc) ->
|
|||
|
||||
init_info(Req, Path, HowToAccess, Extra) ->
|
||||
Info = read_file_info(Path, HowToAccess),
|
||||
{cowboy_rest, Req, {Path, Info, Extra}}.
|
||||
case Info of
|
||||
{direct, #file_info{type = directory}} ->
|
||||
ReqPath = cowboy_req:path(Req),
|
||||
PrefixLen = max(byte_size(ReqPath)-1, 0),
|
||||
case ReqPath of
|
||||
<<_:PrefixLen/binary, $/>> ->
|
||||
dir_with_slash(Req, ReqPath, Path,
|
||||
Info, Extra);
|
||||
_ ->
|
||||
dir_without_slash(Req, ReqPath, Path,
|
||||
Info, Extra)
|
||||
end;
|
||||
_Other ->
|
||||
{cowboy_rest, Req, {Path, Info, Extra}}
|
||||
end.
|
||||
|
||||
dir_without_slash(Req, ReqPath, FilePath, Info, Extra) ->
|
||||
%% no ending slash - redirect to slashed version unless disabled
|
||||
Opts = case lists:keyfind(directory_slash, 1, Extra) of
|
||||
{directory_slash, X} -> X;
|
||||
_ -> true % note: enabled by default
|
||||
end,
|
||||
case slash_options(Opts) of
|
||||
false ->
|
||||
{cowboy_rest, Req, {FilePath, Info, Extra}};
|
||||
Code when is_integer(Code) ->
|
||||
local_redirect(<< ReqPath/binary, <<"/">>/binary >>,
|
||||
Code, Req)
|
||||
end.
|
||||
|
||||
slash_options(false) -> false;
|
||||
slash_options(true) -> slash_options(?DEFAULT_REDIR);
|
||||
slash_options(Code) when is_integer(Code) -> Code.
|
||||
|
||||
dir_with_slash(Req, ReqPath, FilePath, Info, Extra) ->
|
||||
%% URL ends in slash - it's a proper directory reference
|
||||
%% so redirect to index file if enabled
|
||||
Opts = case lists:keyfind(directory_index, 1, Extra) of
|
||||
{directory_index, X} -> X;
|
||||
_ -> false % note: disabled by default
|
||||
end,
|
||||
case index_options(Opts) of
|
||||
false ->
|
||||
{cowboy_rest, Req, {FilePath, Info, Extra}};
|
||||
Module when is_atom(Module) ->
|
||||
{Module, Req, Extra};
|
||||
{Code, File} when is_binary(File) ->
|
||||
%% TODO: also allow list of multiple possible file names
|
||||
local_redirect(<< ReqPath/binary, File/binary >>,
|
||||
Code, Req)
|
||||
end.
|
||||
|
||||
index_options({_, File}=Opt) when is_binary(File) -> Opt;
|
||||
index_options(false) -> false;
|
||||
index_options(true) -> index_options(?DEFAULT_REDIR);
|
||||
index_options(Module) when is_atom(Module) -> Module;
|
||||
index_options(Code) when is_integer(Code) -> {Code, ?DEFAULT_INDEX};
|
||||
index_options(File) -> {?DEFAULT_REDIR, File}.
|
||||
|
||||
local_redirect(NewPath, Code, Req) ->
|
||||
NewURI = cowboy_req:uri(Req, #{path => NewPath}),
|
||||
{ok,
|
||||
cowboy_req:reply(Code, #{<<"Location">> => NewURI}, <<>>, Req),
|
||||
[]}.
|
||||
|
||||
read_file_info(Path, direct) ->
|
||||
case file:read_file_info(Path, [{time, universal}]) of
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue