Skip to content

Commit

Permalink
Add support of wildcards and relative paths to load sub-config files.
Browse files Browse the repository at this point in the history
Now, subconfig and subconfigdir targets accept relative paths, searched
relatively to the configuration location. So for the configuration
"/etc/yaws/yaws.conf", all relative files and directories will be searched from
"/etc/yaws". Of course, absolute paths are always supported.

furthermore, the subconfig target can take Unix-style wildcard strings to
include several files at once. See filelib:wildcard/1 for details.

Last, hidden files, starting by a dot, will be ignored in any cases.
  • Loading branch information
Christopher Faulet committed Jul 10, 2014
1 parent 90e36db commit e81c94a
Show file tree
Hide file tree
Showing 16 changed files with 170 additions and 59 deletions.
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ AC_CONFIG_FILES([
src/yaws_charset.hrl
src/yaws_appdeps.hrl
test/eunit//subconfig_DATA/yaws_absolute.conf
test/support/yaws.conf
test/t1/yaws.conf
test/t2/yaws.conf
Expand Down
22 changes: 20 additions & 2 deletions doc/yaws.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2419,10 +2419,28 @@ \section{Global Part}
\verb+infinity+ is legal but not recommended.

\item \verb+subconfig = File+ ---
Load specified config file.
Load specified config file. Absolute paths or relative ones to
the configuration location are allowed. Unix-style wildcard
strings can be used to include several files at once. See
\verb+filelib:wildcard/1+ for details. Hidden files, starting by a
dot, will be ignored. For example:

\begin{verbatim}
subconfig = /etc/yaws/global.conf
subconfig = /etc/yaws/vhosts/*.conf
\end{verbatim}

Or, relatively to the configuration localtion:

\begin{verbatim}
subconfig = global.conf
subconfig = vhosts/*.conf
\end{verbatim}

\item \verb+subconfigdir = Directory+ ---
Load all config files in specified directory.
Load all config files found in the specified directory. The given
Directory can be an absolute path or relative to the configuration
location. Hidden files, starting by a dot, will be ignored.

\item \verb+x_forwarded_for_log_proxy_whitelist = ListOfUpstreamProxyServerIps+ ---
\textit{This target is deprecated and will be ignored}.
Expand Down
22 changes: 20 additions & 2 deletions man/yaws.conf.5
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,29 @@ but not recommended.

.TP
\fBsubconfig = File\fR
Load specified config file.
Load specified config file. Absolute paths or relative ones to the configuration
location are allowed. Unix-style wildcard strings can be used to include several
files at once. See \fIfilelib:wildcard/1\fR for details. Hidden files, starting
by a dot, will be ignored. For example:

.nf
subconfig = /etc/yaws/global.conf
subconfig = /etc/yaws/vhosts/*.conf
.fi

Or, relatively to the configuration localtion:

.nf
subconfig = global.conf
subconfig = vhosts/*.conf
.fi


.TP
\fBsubconfigdir = Directory\fR
Load all config file in specified directory.
Load all config files found in the specified directory. The given Directory can
be an absolute path or relative to the configuration location. Hidden files,
starting by a dot, will be ignored.

.TP
\fBx_forwarded_for_log_proxy_whitelist = ListOfUpstreamProxyServerIps\fR
Expand Down
115 changes: 62 additions & 53 deletions src/yaws_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -695,45 +695,44 @@ fload(FD, globals, GC, C, Cs, Lno, Chars) ->
fload(FD, globals, GC, C, Cs, Lno+1, Next);

["subconfig", '=', Name] ->
File = filename:absname(Name),
case is_file(File) of
true ->
error_logger:info_msg(
"Yaws: Using subconfig file ~s~n", [File]),
case file:open(File, [read]) of
{ok, FD1} ->
R = (catch fload(FD1, globals, GC, undefined,
Cs, 1, io:get_line(FD1, ''))),
?Debug("FLOAD: ~p", [R]),
case R of
{ok, GC1, Cs1} ->
fload(FD, globals, GC1, C, Cs1, Lno+1,Next);
Err ->
Err
end;
{ok, Config} = file:pid2name(FD),
ConfPath = filename:dirname(filename:absname(Config)),
File = filename:absname(Name, ConfPath),
case {is_file(File), is_wildcard(Name)} of
{true,_} ->
case subconfigfile(File, GC, Cs) of
{ok, GC1, Cs1} ->
fload(FD, globals, GC1, C, Cs1, Lno+1,Next);
Err ->
{error, ?F("Can't open config file ~s:~p",
[File,Err])}
Err
end;
false ->
{error, ?F("Expect filename at line ~w", [Lno])}
{false,true} ->
Names = filelib:wildcard(Name, ConfPath),
Files = [filename:absname(N, ConfPath)
|| N <- lists:sort(Names)],
case subconfigfiles(Files, GC, Cs) of
{ok, GC1, Cs1} ->
fload(FD, globals, GC1, C, Cs1,
Lno+1, Next);
Err ->
Err
end;
{false,false} ->
{error, ?F("Expect filename or wildcard at line ~w"
" [subconfig: ~s]", [Lno, Name])}
end;

["subconfigdir", '=', Name] ->
Dir = filename:absname(Name),
{ok, Config} = file:pid2name(FD),
ConfPath = filename:dirname(filename:absname(Config)),
Dir = filename:absname(Name, ConfPath),
case is_dir(Dir) of
true ->
case file:list_dir(Dir) of
{ok, Names} ->
Sorted = lists:sort(Names),
Paths = lists:map(
fun(N) ->
filename:absname(N, Dir)
end, Sorted),
Fold = lists:foldl(
fun subconfigdir_fold/2,
{ok, GC, Cs}, Paths),
case Fold of
Files = [filename:absname(N, Dir)
|| N <- lists:sort(Names)],
case subconfigfiles(Files, GC, Cs) of
{ok, GC1, Cs1} ->
fload(FD, globals, GC1, C, Cs1,
Lno+1, Next);
Expand Down Expand Up @@ -2228,6 +2227,12 @@ is_file(Val) ->
false
end.

is_wildcard(Val) ->
(lists:member($*, Val) orelse
lists:member($?, Val) orelse
(lists:member($[, Val) andalso lists:member($], Val)) orelse
(lists:member(${, Val) andalso lists:member($}, Val))).


%% tokenizer
toks(Lno, Chars) ->
Expand Down Expand Up @@ -3031,31 +3036,35 @@ parse_auth_ips([Str|Rest], Result) ->
end.


subconfigdir_fold(_File, {error, _Err}=Acc) ->
Acc;
subconfigdir_fold(File, {ok, GCp, Csp}=Acc) ->
case is_file(File) of
true ->
error_logger:info_msg("Yaws: Using subconfig file ~s~n", [File]),
case file:open(File, [read]) of
{ok, FD1} ->
R = (catch fload(FD1,
globals,
GCp,
undefined,
Csp,
1,
io:get_line(FD1, ''))),
?Debug("FLOAD: ~p", [R]),
R;
_ ->
{error, "Can't open config file " ++ File}
end;
false ->
%% Ignore subdirectories
Acc

subconfigfiles([], GC, Cs) ->
{ok, GC, Cs};
subconfigfiles([File|Files], GC, Cs) ->
case filename:basename(File) of
[$.|_] ->
error_logger:info_msg("Yaws: Ignore subconfig file ~s~n", [File]),
subconfigfiles(Files, GC, Cs);
_ ->
case subconfigfile(File, GC, Cs) of
{ok, GC1, Cs1} -> subconfigfiles(Files, GC1, Cs1);
Err -> Err
end
end.

subconfigfile(File, GC, Cs) ->
error_logger:info_msg("Yaws: Using subconfig file ~s~n", [File]),
case file:open(File, [read]) of
{ok, FD} ->
R = (catch fload(FD, globals, GC, undefined,
Cs, 1, io:get_line(FD, ''))),
?Debug("FLOAD: ~p", [R]),
R;
Err ->
{error, ?F("Can't open config file ~s: ~p", [File,Err])}
end.



str2term(Str0) ->
Str=Str0++".",
{ok,Tokens,_EndLine} = erl_scan:string(Str),
Expand Down
5 changes: 3 additions & 2 deletions test/eunit/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ MODULES = multipart_post_parsing.erl \
gconf.erl \
sconf.erl \
yaws_rpc_test.erl \
proc_cleanup.erl
proc_cleanup.erl \
subconfig.erl

EXTRA_DIST = $(MODULES) cookies.dump setcookies.dump
EXTRA_DIST = $(MODULES) cookies.dump setcookies.dump subconfig_DATA

EBIN_FILES=$(MODULES:%.erl=%.beam)

Expand Down
30 changes: 30 additions & 0 deletions test/eunit/subconfig.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-module(subconfig).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").

-include("yaws.hrl").
-include("tftest.hrl").

absolute_subconfig_test() ->
Env = #env{debug = false,
conf = {file, ?builddir++"/subconfig_DATA/yaws_absolute.conf"}},

{ok, _GC, SCs} = yaws_config:load(Env),
check_sconfs(lists:flatten(SCs)).

relative_subconfig_test() ->
Env = #env{debug = false,
conf = {file, ?srcdir++"/subconfig_DATA/yaws_relative.conf"}},

{ok, _GC, SCs} = yaws_config:load(Env),
check_sconfs(lists:flatten(SCs)).

check_sconfs(SCs) ->
?assertEqual(5, length(SCs)),
?assert(lists:keymember(80, #sconf.port, SCs)),
?assert(lists:keymember(8001, #sconf.port, SCs)),
?assert(lists:keymember(8002, #sconf.port, SCs)),
?assert(lists:keymember(8003, #sconf.port, SCs)),
?assert(lists:keymember(8004, #sconf.port, SCs)),
ok.

5 changes: 5 additions & 0 deletions test/eunit/subconfig_DATA/subconfig.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<server vhost_subconfig>
port = 80
listen = 0.0.0.0
docroot = /tmp
</server>
1 change: 1 addition & 0 deletions test/eunit/subconfig_DATA/subconfig.d/.hidden.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invalid_param = error
1 change: 1 addition & 0 deletions test/eunit/subconfig_DATA/subconfig.d/ignored
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invalid_param = error
5 changes: 5 additions & 0 deletions test/eunit/subconfig_DATA/subconfig.d/subconfig1.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<server vhost_subconfigdir1>
port = 8001
listen = 0.0.0.0
docroot = /tmp
</server>
5 changes: 5 additions & 0 deletions test/eunit/subconfig_DATA/subconfig.d/subconfig2.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<server vhost_subconfigdir2>
port = 8002
listen = 0.0.0.0
docroot = /tmp
</server>
1 change: 1 addition & 0 deletions test/eunit/subconfig_DATA/subconfigdir.d/.hidden.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invalid_param = error
5 changes: 5 additions & 0 deletions test/eunit/subconfig_DATA/subconfigdir.d/subconfigdir1.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<server vhost_subconfigdir1>
port = 8003
listen = 0.0.0.0
docroot = /tmp
</server>
5 changes: 5 additions & 0 deletions test/eunit/subconfig_DATA/subconfigdir.d/subconfigdir2.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<server vhost_subconfigdir2>
port = 8004
listen = 0.0.0.0
docroot = /tmp
</server>
3 changes: 3 additions & 0 deletions test/eunit/subconfig_DATA/yaws_absolute.conf.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
subconfigdir = @abs_srcdir@/subconfigdir.d
subconfig = @abs_srcdir@/subconfig.conf
subconfig = @abs_srcdir@/subconfig.d/*.conf
3 changes: 3 additions & 0 deletions test/eunit/subconfig_DATA/yaws_relative.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
subconfigdir = subconfigdir.d
subconfig = subconfig.conf
subconfig = subconfig.d/*.conf

0 comments on commit e81c94a

Please sign in to comment.