Permalink
Browse files

Respect virtual hosts order when the configuration is reloaded

During a reload, when a virtual host is added or updated, it must be at the same
position than in the configuration file. With this fix, it is possible to
reorder virtual hosts, or add new ones at any position.
  • Loading branch information...
1 parent 15a171f commit 68f1f7c92f8ae65a2f097885c7bbd6b5a01a2b81 @capflam capflam committed Feb 26, 2014
Showing with 78 additions and 65 deletions.
  1. +15 −1 src/yaws.erl
  2. +38 −35 src/yaws_config.erl
  3. +25 −29 src/yaws_server.erl
View
16 src/yaws.erl
@@ -153,7 +153,7 @@
-export([sconf_to_srvstr/1,
redirect_host/2, redirect_port/1,
redirect_scheme_port/1, redirect_scheme/1,
- tmpdir/0, tmpdir/1, mktemp/1, split_at/2,
+ tmpdir/0, tmpdir/1, mktemp/1, split_at/2, insert_at/3,
id_dir/1, ctl_file/1]).
-export([parse_ipmask/1, match_ipmask/2]).
@@ -2518,6 +2518,20 @@ split_at([H|T], Char, Ack) ->
split_at([], _Char, Ack) ->
{lists:reverse(Ack), []}.
+%% insert an elemant at a given position into a list
+insert_at(Elm, 0, Ls) ->
+ Ls ++ [Elm];
+insert_at(Elm, Pos, Ls) ->
+ insert_at(Elm, Pos, Ls, []).
+
+insert_at(Elm, _, [], Res) ->
+ lists:reverse([Elm|Res]);
+insert_at(Elm, 1, Ls, Res) ->
+ lists:reverse([Elm|Res]) ++ Ls;
+insert_at(Elm, Pos, [H|T], Res) ->
+ insert_at(Elm, Pos-1, T, [H|Res]).
+
+
%% Parse an Ip address or an Ip address range
%% Return Ip || {IpMin, IpMax} where:
View
73 src/yaws_config.erl
@@ -23,7 +23,7 @@
load_mime_types_module/2,
compile_and_load_src_dir/1,
search_sconf/2, search_group/2,
- update_sconf/2, delete_sconf/2,
+ update_sconf/3, delete_sconf/2,
eq_sconfs/2, soft_setconf/4, hard_setconf/2,
can_hard_gc/2, can_soft_setconf/4,
can_soft_gc/2, verify_upgrade_args/2, toks/2]).
@@ -68,8 +68,7 @@ load(E) ->
end,
GC3 = ?gc_set_debug(GC2, E#env.debug),
GC4 = GC3#gconf{trace = E#env.trace},
- R = (catch fload(FD, globals, GC4, undefined,
- [], 1, io:get_line(FD, ''))),
+ R = fload(FD, GC4),
?Debug("FLOAD: ~p", [R]),
case R of
{ok, GC5, Cs} ->
@@ -545,14 +544,14 @@ arrange([C|Tail], start, [], B) ->
arrange([], _, [], B) ->
B;
arrange([], _, A, B) ->
- [A | B];
+ [lists:reverse(A) | B];
arrange([C1|Tail], {in, C0}, A, B) ->
if
C1#sconf.listen == C0#sconf.listen,
C1#sconf.port == C0#sconf.port ->
arrange(Tail, {in, C0}, [set_server(C1)|A], B);
true ->
- arrange(Tail, {in, C1}, [set_server(C1)], [A|B])
+ arrange(Tail, {in, C1}, [set_server(C1)], [lists:reverse(A)|B])
end.
@@ -666,6 +665,14 @@ string_to_node_mod_fun(String) ->
%% two states, global, server
+fload(FD, GC0) ->
+ R = (catch fload(FD, globals, GC0, undefined, [], 1, io:get_line(FD, ''))),
+ case R of
+ {ok, GC1, Cs} -> {ok, GC1, lists:reverse(Cs)};
+ Err -> Err
+ end.
+
+
fload(FD, globals, GC, _C, Cs, _Lno, eof) ->
file:close(FD),
{ok, GC, Cs};
@@ -2626,7 +2633,7 @@ ssl_start() ->
%% search for an SC within Pairs that have the same, listen,port,ssl,severname
-%% Return {Pid, SC} or false
+%% Return {Pid, SC, Scs} or false
%% Pairs is the pairs in yaws_server #state{}
search_sconf(NewSC, Pairs) ->
case lists:zf(
@@ -2669,19 +2676,17 @@ search_group(SC, Pairs) ->
%% Return a new Pairs list with one SC updated
-update_sconf(NewSC, Pairs) ->
+update_sconf(NewSc, Pos, Pairs) ->
lists:map(
fun({Pid, Scs}) ->
- {Pid,
- lists:map(fun(SC) ->
- case same_sconf(SC, NewSC) of
- true ->
- NewSC;
- false ->
- SC
- end
- end, Scs)
- }
+ case same_virt_srv(hd(Scs), NewSc) of
+ true ->
+ L2 = lists:keydelete(NewSc#sconf.servername,
+ #sconf.servername, Scs),
+ {Pid, yaws:insert_at(NewSc, Pos, L2)};
+ false ->
+ {Pid, Scs}
+ end
end, Pairs).
@@ -2711,11 +2716,6 @@ same_virt_srv(_,_) ->
false.
-same_sconf(S, NewSc) ->
- same_virt_srv(S, NewSc) andalso
- S#sconf.servername == NewSc#sconf.servername.
-
-
eq_sconfs(S1,S2) ->
(S1#sconf.port == S2#sconf.port andalso
S1#sconf.flags == S2#sconf.flags andalso
@@ -2768,14 +2768,14 @@ soft_setconf(GC, Groups, OLDGC, OldGroups) ->
compile_and_load_src_dir(GC),
Grps = load_mime_types_module(GC, Groups),
Rems = remove_old_scs(lists:flatten(OldGroups), Grps),
- Adds = soft_setconf_scs(lists:flatten(Grps), OldGroups),
+ Adds = soft_setconf_scs(lists:flatten(Grps), 1, OldGroups),
lists:foreach(
fun({delete_sconf, SC}) ->
delete_sconf(SC);
- ({add_sconf, SC}) ->
- add_sconf(SC);
- ({update_sconf, SC}) ->
- update_sconf(SC)
+ ({add_sconf, N, SC}) ->
+ add_sconf(N, SC);
+ ({update_sconf, N, SC}) ->
+ update_sconf(N, SC)
end, Rems ++ Adds).
@@ -2806,19 +2806,19 @@ remove_old_scs([Sc|Scs], NewGroups) ->
remove_old_scs([],_) ->
[].
-soft_setconf_scs([Sc|Scs], OldGroups) ->
+soft_setconf_scs([Sc|Scs], N, OldGroups) ->
case find_group(Sc, OldGroups) of
false ->
- [{add_sconf,Sc} | soft_setconf_scs(Scs, OldGroups)];
+ [{add_sconf,N,Sc} | soft_setconf_scs(Scs, N+1, OldGroups)];
{true, G} ->
case find_sc(Sc, G) of
false ->
- [{add_sconf, Sc} | soft_setconf_scs(Scs, OldGroups)];
+ [{add_sconf,N,Sc} | soft_setconf_scs(Scs,N+1,OldGroups)];
{true, _OldSc} ->
- [{update_sconf,Sc} | soft_setconf_scs(Scs, OldGroups)]
+ [{update_sconf,N,Sc} | soft_setconf_scs(Scs,N+1,OldGroups)]
end
end;
-soft_setconf_scs([],_) ->
+soft_setconf_scs([], _, _) ->
[].
@@ -2934,11 +2934,14 @@ verify_upgrade_args(GC, Groups0) when is_record(GC, gconf) ->
add_sconf(SC) ->
- ok= gen_server:call(yaws_server, {add_sconf, SC}, infinity),
+ add_sconf(-1, SC).
+
+add_sconf(Pos, SC) ->
+ ok= gen_server:call(yaws_server, {add_sconf, Pos, SC}, infinity),
ok = yaws_log:add_sconf(SC).
-update_sconf(SC) ->
- ok = gen_server:call(yaws_server, {update_sconf, SC}, infinity).
+update_sconf(Pos, SC) ->
+ ok = gen_server:call(yaws_server, {update_sconf, Pos, SC}, infinity).
delete_sconf(SC) ->
ok = gen_server:call(yaws_server, {delete_sconf, SC}, infinity),
View
54 src/yaws_server.erl
@@ -327,19 +327,20 @@ handle_call(check_certs, _From, State) ->
end, State#state.pairs),
{reply, L, State};
-handle_call({update_sconf, NewSc}, From, State) ->
+handle_call({update_sconf, Pos, NewSc}, From, State) ->
case yaws_config:search_sconf(NewSc, State#state.pairs) of
- {Pid, OldSc, _Group} ->
- case yaws_config:eq_sconfs(OldSc,NewSc) of
+ {Pid, OldSc, Group} ->
+ OldPos = string:str(Group, [OldSc]),
+ case (yaws_config:eq_sconfs(OldSc,NewSc) andalso OldPos == Pos) of
true ->
error_logger:info_msg("Keeping conf for ~s intact\n",
[yaws:sconf_to_srvstr(OldSc)]),
- {reply, ok, State};
+ {reply, ok, State};
false ->
- Pid ! {update_sconf, NewSc, OldSc, From, self()},
+ Pid ! {update_sconf, Pos, NewSc, OldSc, From, self()},
receive
{updated_sconf, Pid, NewSc2} ->
- P2 = yaws_config:update_sconf(NewSc2,
+ P2 = yaws_config:update_sconf(NewSc2, Pos,
State#state.pairs),
{noreply, State#state{pairs = P2}}
after 2000 ->
@@ -351,8 +352,8 @@ handle_call({update_sconf, NewSc}, From, State) ->
end;
-handle_call({delete_sconf, SC}, From, State) ->
- case yaws_config:search_sconf(SC, State#state.pairs) of
+handle_call({delete_sconf, Sc}, From, State) ->
+ case yaws_config:search_sconf(Sc, State#state.pairs) of
{Pid, OldSc, Group} when length(Group) == 1 ->
error_logger:info_msg("Terminate whole ~s virt server group \n",
[yaws:sconf_to_srvstr(OldSc)]),
@@ -367,24 +368,24 @@ handle_call({delete_sconf, SC}, From, State) ->
{reply, {error, "No matching group"}, State}
end;
-handle_call({add_sconf, SC}, From, State) ->
- case yaws_config:search_group(SC, State#state.pairs) of
- [{Pid, Group}] ->
- Pid ! {add_sconf, From, SC, self()},
+handle_call({add_sconf, Pos, Sc}, From, State) ->
+ case yaws_config:search_group(Sc, State#state.pairs) of
+ [{Pid, _Group}] ->
+ Pid ! {add_sconf, From, Pos, Sc, self()},
receive
- {added_sconf, Pid, SC2} ->
- P2 = lists:keyreplace(Pid, 1, State#state.pairs,
- {Pid, Group ++ [SC2]}),
+ {added_sconf, Pid, Sc2} ->
+ P2 = yaws_config:update_sconf(Sc2, Pos,
+ State#state.pairs),
{noreply, State#state{pairs = P2}}
after 2000 ->
{reply, {error, "Failed to add new conf"}, State}
end;
[] ->
%% Need to create a new group
error_logger:info_msg("Creating new virt server ~s\n",
- [yaws:sconf_to_srvstr(SC)]),
+ [yaws:sconf_to_srvstr(Sc)]),
GC = State#state.gc,
- case start_group(GC, [SC]) of
+ case start_group(GC, [Sc]) of
false ->
{reply, ok, State};
{true, Pair} ->
@@ -716,7 +717,7 @@ gserv_loop(GS, Ready, Rnum, Last) ->
%% This code will shutdown all ready procs as well as the
%% acceptor()
- {update_sconf, NewSc, OldSc, From, Updater} ->
+ {update_sconf, Pos, NewSc, OldSc, From, Updater} ->
case lists:member(OldSc, GS#gs.group) of
false ->
error_logger:error_msg("gserv: No found SC ~p/~p~n",
@@ -739,15 +740,10 @@ gserv_loop(GS, Ready, Rnum, Last) ->
end,
stop_ready(Ready, Last),
NewSc2 = clear_ets_complete(NewSc1),
- %% Need to insert the sconf at the same position
- %% it previously was
- NewG = lists:map(fun(Sc) when Sc == OldSc->
- NewSc2;
- (Other) ->
- Other
- end, GS#gs.group),
-
- GS2 = GS#gs{group = NewG},
+ GS2 = GS#gs{group = yaws:insert_at(
+ NewSc2, Pos,
+ lists:delete(OldSc, GS#gs.group)
+ )},
Ready2 = [],
Updater ! {updated_sconf, self(), NewSc2},
gen_server:reply(From, ok),
@@ -783,7 +779,7 @@ gserv_loop(GS, Ready, Rnum, Last) ->
?MODULE:gserv_loop(GS2, Ready2, 0, New)
end;
- {add_sconf, From, SC0, Adder} ->
+ {add_sconf, From, Pos, SC0, Adder} ->
SC = case ?sc_has_statistics(SC0) of
true ->
{ok, Pid} = yaws_stats:start_link(),
@@ -794,7 +790,7 @@ gserv_loop(GS, Ready, Rnum, Last) ->
end,
stop_ready(Ready, Last),
SC2 = setup_ets(SC),
- GS2 = GS#gs{group = GS#gs.group ++ [SC2]},
+ GS2 = GS#gs{group = yaws:insert_at(SC2, Pos, GS#gs.group)},
Ready2 = [],
Adder ! {added_sconf, self(), SC2},
gen_server:reply(From, ok),

0 comments on commit 68f1f7c

Please sign in to comment.