fuzed 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ puts("You must specify the absolute path to your Rails root as the first argument") and exit unless ARGV[0]
4
+
5
+ rails_public_dir = File.join(ARGV[0], 'public')
6
+
7
+ SUBSTITUTIONS =
8
+ {:rails_public_dir => rails_public_dir,
9
+ :port => ARGV[1] || "80"}
10
+
11
+ template = File.join(File.dirname(__FILE__), *%w[.. templates fuzed.conf])
12
+
13
+ conf = File.open(template).read
14
+ SUBSTITUTIONS.each_pair do |key, data|
15
+ repl_key = '{{ ' + key.to_s.upcase + ' }}'
16
+ conf.gsub!(repl_key, data)
17
+ end
18
+
19
+ File.open('fuzed.conf', 'w') do |f|
20
+ f.write conf
21
+ end
22
+
23
+ puts 'successfully wrote fuzed.conf in current directory'
Binary file
@@ -0,0 +1,55 @@
1
+ -module(port_wrapper).
2
+ -export([wrap/1, send/2, send_from/3, shutdown/1, rpc/2]).
3
+ -author('Dave Fayram').
4
+
5
+ wrap(Command) ->
6
+ spawn(fun() -> process_flag(trap_exit, true), Port = create_port(Command), link(Port), loop(Port, [
7
+ ]) end).
8
+
9
+ rpc(WrappedPort, Message) ->
10
+ send(WrappedPort, Message),
11
+ receive
12
+ {WrappedPort, Result} -> Result
13
+ after 10000 ->
14
+ {WrappedPort, timed_out}
15
+ end.
16
+
17
+ send(WrappedPort, Message) ->
18
+ WrappedPort ! {self(), {command, term_to_binary(Message)}},
19
+ WrappedPort.
20
+
21
+ send_from(Target, WrappedPort, Message) ->
22
+ WrappedPort ! {Target, {command, term_to_binary(Message)}},
23
+ WrappedPort.
24
+
25
+
26
+ shutdown(WrappedPort) ->
27
+ WrappedPort ! shutdown,
28
+ true.
29
+
30
+ create_port(Command) ->
31
+ open_port({spawn, Command}, [{packet, 4}, nouse_stdio, exit_status, binary]).
32
+
33
+ loop(Port, Monitors) ->
34
+ receive
35
+ shutdown ->
36
+ port_close(Port),
37
+ exit(shutdown);
38
+ {Source, {command, Message}} ->
39
+ Port ! {self(), {command, Message}},
40
+ receive
41
+ {Port, {data, Result}} ->
42
+ Source ! {self(), binary_to_term(Result)}
43
+ end,
44
+ loop(Port,Monitors);
45
+
46
+ {monitor, Proc} when is_pid(Proc) ->
47
+ loop(Port, [Proc|Monitors]);
48
+
49
+ {Port, {exit_status, _Code}} ->
50
+ %port_close(Port)
51
+ exit(external_failure);
52
+ Any ->
53
+ io:format("----------~nWrapper got: ~p~n----------~n", [Any]),
54
+ loop(Port, Monitors)
55
+ end.
@@ -0,0 +1,147 @@
1
+ -module(rails_connection_pool).
2
+ -compile(export_all).
3
+
4
+
5
+ %% Convenience Function
6
+ simple_handle_request(Arg,ServerInfo) ->
7
+ {Source, Resource} = rails_connection_pool:get(),
8
+ Response = rails_forwarder:handle_request(Resource, Arg, ServerInfo, 10000),
9
+ rails_connection_pool:refund({Source,Resource}),
10
+ Response.
11
+
12
+
13
+ handle_request(Arg,ServerInfo) ->
14
+ handle_request_helper(Arg,ServerInfo,0).
15
+
16
+ handle_request_helper(_Arg,_ServerInfo,Retries) when Retries > 1 ->
17
+ throw(timed_out);
18
+ handle_request_helper(Arg,ServerInfo,Retries) ->
19
+ Remote = fun(A,S,Target) ->
20
+ {Source, Handler} = rails_connection_pool:get(),
21
+ Response = rails_forwarder:rails_handle_request(Handler, A, S, 10000),
22
+ Target ! {rails_response, Response},
23
+ rails_connection_pool:refund({Source, Handler}) end,
24
+ _RequestProc = spawn(Remote(Arg,ServerInfo,self())),
25
+ receive
26
+ {rails_response, Response} ->
27
+ Response
28
+ after 5000 ->
29
+ handle_request_helper(Arg,ServerInfo, Retries+1)
30
+ end.
31
+
32
+
33
+ %% Server manipulation
34
+ start() ->
35
+ global:register_name(?MODULE, spawn(
36
+ fun() ->
37
+ process_flag(trap_exit, true),
38
+ rails_connection_pool:loop([],[]) end
39
+ )
40
+ ).
41
+
42
+ add({Node, Proc}) when is_pid(Proc) ->
43
+ global:send(?MODULE, {add, {Node, Proc}}),
44
+ ok.
45
+
46
+ remove(Rsrc) ->
47
+ global:send(?MODULE, {remove, Rsrc}),
48
+ ok.
49
+
50
+ get() ->
51
+ global:send(?MODULE, {get, self()}),
52
+ receive
53
+ {node, X} ->
54
+ X
55
+ end.
56
+
57
+ refund(Node) ->
58
+ global:send(?MODULE, {refund, Node}),
59
+ ok.
60
+
61
+ list() ->
62
+ global:send(?MODULE, {list, self()}),
63
+ receive
64
+ {nodes, A} ->
65
+ A
66
+ end.
67
+
68
+ list_all() ->
69
+ global:send(?MODULE, {list_all, self()}),
70
+ receive
71
+ {all_nodes, A} ->
72
+ A
73
+ end.
74
+
75
+ remove_server(Server) ->
76
+ global:send(?MODULE, {remove_server, Server}),
77
+ ok.
78
+
79
+ remove_all() ->
80
+ global:send(?MODULE, {remove_all}),
81
+ ok.
82
+
83
+ remove_server_filter(Server, {Server, _X}) -> false;
84
+ remove_server_filter(_Server, {_NotServer, _X}) -> true.
85
+
86
+ loop([],A) ->
87
+ receive
88
+ {add, {Node, Proc}} when is_pid(Proc) ->
89
+ erlang:link(Proc),
90
+ loop([{Node,Proc}],[{Node,Proc}|A]);
91
+ {list, Pid} ->
92
+ Pid ! {nodes, []},
93
+ loop([],A);
94
+ {list_all, Pid} ->
95
+ Pid ! {all_nodes, A},
96
+ loop([],A);
97
+ {refund,Node} ->
98
+ Membership = lists:member(Node,A),
99
+ if
100
+ Membership ->
101
+ loop([Node],A);
102
+ true ->
103
+ loop([],A)
104
+ end;
105
+ {'EXIT', Pid, _Reason} ->
106
+ FilterFun = fun({_Node,MPid}) -> MPid /= Pid end,
107
+ loop([],lists:filter(FilterFun, A))
108
+ end;
109
+ loop(X,A) ->
110
+ receive
111
+ {add, {Node, Proc}} when is_pid(Proc)->
112
+ erlang:link(Proc),
113
+ I = {Node, Proc},
114
+ loop([I|X], [I|A]);
115
+ {remove, I} ->
116
+ loop(lists:delete(I,X), lists:delete(I,A));
117
+ {remove_server, Server} ->
118
+ PurgedX = lists:filter(fun(Z) -> remove_server_filter(Server, Z) end, X),
119
+ PurgedA = lists:filter(fun(Z) -> remove_server_filter(Server, Z) end, A),
120
+ loop(PurgedX, PurgedA);
121
+ {remove_all} ->
122
+ loop([],[]);
123
+ {list, Pid} ->
124
+ Pid ! {nodes, X},
125
+ loop(X,A);
126
+ {list_all, Pid} ->
127
+ Pid ! {all_nodes, A},
128
+ loop(X,A);
129
+ {get, Pid} ->
130
+ [Node|Rest] = X,
131
+ Pid ! {node, Node},
132
+ loop(Rest,A);
133
+ {refund,Node} ->
134
+ Membership = lists:member(Node,A),
135
+ if
136
+ Membership ->
137
+ loop(X ++ [Node],A);
138
+ true ->
139
+ loop(X,A)
140
+ end;
141
+ {'EXIT', Pid, _Reason} ->
142
+ FilterFun = fun({_Node,MPid}) -> MPid /= Pid end,
143
+ loop(lists:filter(FilterFun,X),lists:filter(FilterFun, A));
144
+ Other ->
145
+ io:format("~p loop(X,A) Received unknown message: ~p~n", [?MODULE, Other]),
146
+ loop(X,A)
147
+ end.
@@ -0,0 +1,112 @@
1
+ -module(rails_forwarder).
2
+ -compile(export_all).
3
+ -include("../yaws_includes/yaws_api.hrl").
4
+ -include("../yaws_includes/yaws.hrl").
5
+
6
+ %-export([rails_create_responder/1, rails_create_responders/2, rails_handle_request/3,
7
+ % rails_handle_request_for/3, get_rails_response/2, prepare_request/1, decode_result/1]).
8
+
9
+ %create_responder(Command) ->
10
+ % port_wrapper:wrap(Command).
11
+ %
12
+ %create_responders(Command, N) ->
13
+ % create_responders_helper(Command, N, []).
14
+ %
15
+ %create_responders_helper(_Command, 0, Results) ->
16
+ % Results;
17
+ %create_responders_helper(Command, N, Results) ->
18
+ % create_responders_helper(Command, N-1, [create_responder(Command)|Results]).
19
+
20
+ handle_request(Resource, Request, ServerOptions, Timeout) ->
21
+ {_Node, Responder} = Resource,
22
+ handle_request_for(Responder, Request, ServerOptions, self()),
23
+ try get_rails_response(Responder, Timeout) of
24
+ Any -> Any
25
+ catch
26
+ throw:timed_out ->
27
+ io:format("--- Timed out, removing resource and retrying!"),
28
+ rails_connection_pool:remove(Resource),
29
+ rails_forwarder:handle_request(rails_connection_pool:get(), Request, ServerOptions, Timeout)
30
+ end.
31
+
32
+ handle_request_for(Responder, Request, ServerOptions, Target) ->
33
+ Data = {request, prepare_request(Request, ServerOptions)},
34
+ port_wrapper:send_from(Target, Responder, Data).
35
+
36
+
37
+ get_rails_response(Responder, Timeout) ->
38
+ receive
39
+ {Responder, Result} ->
40
+ decode_result(Result);
41
+ Any ->
42
+ io:format("Unexpected message in get_rails_response: ~p~n", [Any])
43
+ after Timeout ->
44
+ throw(timed_out)
45
+ end.
46
+
47
+
48
+ % Fugly data munging
49
+ prepare_request(Request, ServerOptions) ->
50
+ Headers = Request#arg.headers,
51
+ {convert_method(Request), convert_version(Request), convert_querypath(Request),
52
+ {querydata, prep(Request#arg.querydata)}, {servername, prep(ServerOptions#sconf.servername)},
53
+ {headers, convert_headers(Request#arg.headers)},
54
+ {cookies, list_to_tuple(lists:map(fun(X) -> prep(X) end, Headers#headers.cookie))},
55
+ {pathinfo, prep(ServerOptions#sconf.docroot)},
56
+ {postdata, Request#arg.clidata}}. % TODO: prepare request for railsification
57
+
58
+ decode_result({response, ResponseData}) ->
59
+ convert_response(ResponseData).
60
+
61
+ convert_response(EhtmlTuple) ->
62
+ {Status, AllHeaders, Html} = EhtmlTuple,
63
+ {allheaders, HeaderList} = AllHeaders,
64
+ ProcessedHeaderList = lists:map(fun({header, Name, Value}) -> {header, [binary_to_list(Name) ++ ":", binary_to_list(Value)]} end,
65
+ tuple_to_list(HeaderList)),
66
+ {html, RawResult} = Html,
67
+ [Status, {allheaders, ProcessedHeaderList}, {html, binary_to_list(RawResult)}].
68
+
69
+ prep(A) when is_list(A) -> list_to_binary(A);
70
+ prep(A) -> A.
71
+
72
+ convert_method(Request) ->
73
+ R = Request#arg.req,
74
+ {http_request,Method,{_Type,_Path},_} = R,
75
+ {method, Method}.
76
+
77
+ convert_querypath(Request) ->
78
+ R = Request#arg.req,
79
+ {http_request,_Method,{_Type,Path},_} = R,
80
+ {querypath, prep(Path)}.
81
+
82
+ convert_version(Request) ->
83
+ R = Request#arg.req,
84
+ {http_request,_Method,{_Type,_Path},Version} = R,
85
+ {http_version, Version}.
86
+
87
+ convert_req(R) ->
88
+ {http_request,Method,{_Type,Path},_} = R,
89
+ {Method, prep(Path)}.
90
+
91
+ convert_headers(A) ->
92
+ NormalHeaders = [{connection, prep(A#headers.connection)},
93
+ {accept, prep(A#headers.accept)},
94
+ {host, prep(A#headers.host)},
95
+ {if_modified_since, prep(A#headers.if_modified_since)},
96
+ {if_match, prep(A#headers.if_match)},
97
+ {if_none_match, prep(A#headers.if_none_match)},
98
+ {if_range, prep(A#headers.if_range)},
99
+ {if_unmodified_since, prep(A#headers.if_unmodified_since)},
100
+ {range, prep(A#headers.range)},
101
+ {referer, prep(A#headers.referer)},
102
+ {user_agent, prep(A#headers.user_agent)},
103
+ {accept_ranges, prep(A#headers.accept_ranges)},
104
+ {keep_alive, prep(A#headers.keep_alive)},
105
+ {location, prep(A#headers.location)},
106
+ {content_length, prep(A#headers.content_length)},
107
+ {content_type, prep(A#headers.content_type)},
108
+ {content_encoding, prep(A#headers.content_encoding)},
109
+ {authorization, prep(A#headers.authorization)},
110
+ {transfer_encoding, prep(A#headers.transfer_encoding)}],
111
+ SpecialHeaders = lists:map(fun({http_header, _Len, Name, _, Value}) -> {prep(Name), prep(Value)} end, A#headers.other),
112
+ list_to_tuple([{Name, Res} || {Name, Res} <- NormalHeaders, Res /= undefined] ++ SpecialHeaders).
@@ -0,0 +1,108 @@
1
+ %%%-------------------------------------------------------------------
2
+ %%% File : /Users/dfayram/Projects/concilium/elibs/resource_manager.erl
3
+ %%% Author : David Fayram
4
+ %%%-------------------------------------------------------------------
5
+ -module(resource_manager).
6
+ -behaviour(gen_server).
7
+
8
+ %% API exports
9
+ -export([start_link/3, start/3,nodes/0,nodecount/0,change_nodecount/1,cycle/0]).
10
+
11
+ %% gen_server callback exports
12
+ -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
13
+ terminate/2, code_change/3]).
14
+
15
+ %% Erlang records are ugly.
16
+ -record(state, {generator = fun() -> undefined end,
17
+ terminator = fun(_) -> undefined end,
18
+ nodecount = 4,
19
+ nodes = [],
20
+ term_hook = fun(_) -> undefined end
21
+ }).
22
+
23
+ %% External call functions
24
+
25
+ % Note the local server, one of these should run on every
26
+ % node serving up rails responders.
27
+ start_link(Generator, Terminator, NumNodes) ->
28
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [Generator, Terminator, NumNodes], []).
29
+ start(Generator, Terminator, NumNodes) ->
30
+ gen_server:start({local, ?MODULE}, ?MODULE, [Generator, Terminator, NumNodes], []).
31
+
32
+ nodes() -> gen_server:call(?MODULE, nodes).
33
+ nodecount() -> gen_server:call(?MODULE, nodecount).
34
+ change_nodecount(NewNodecount) -> gen_server:cast(?MODULE, {change_nodecount, NewNodecount}).
35
+ cycle() -> gen_server:cast(?MODULE, cycle).
36
+
37
+ %% GEN_SERVER callbacks.
38
+ init([Generator, Terminator, NumNodes]) ->
39
+ process_flag(trap_exit, true),
40
+ Nodes = spawn_nodes(Generator, NumNodes),
41
+ {ok, #state{generator = Generator, nodecount = NumNodes,
42
+ nodes = Nodes, terminator = Terminator}}.
43
+
44
+ handle_call(term_hook, _From, State) ->
45
+ {reply, State#state.term_hook, State};
46
+ handle_call({term_hook, Hook}, _From, State) when is_function(Hook, 1) ->
47
+ {reply, State#state.term_hook, State#state{term_hook = Hook}};
48
+ handle_call(nodecount,_From,State) ->
49
+ {reply, State#state.nodecount, State};
50
+ handle_call(nodes, _From, State) ->
51
+ {reply, State#state.nodes, State}.
52
+
53
+ handle_cast(cycle, State) ->
54
+ drop_nodes(State#state.terminator, State#state.nodes),
55
+ {noreply, State#state{nodes=spawn_nodes(State#state.generator, State#state.nodecount)}};
56
+ handle_cast({change_nodecount, NewCount}, S) when is_number(NewCount) ->
57
+ Count = S#state.nodecount,
58
+ if
59
+ NewCount > Count ->
60
+ {noreply,
61
+ S#state{nodecount = NewCount,
62
+ nodes = spawn_nodes(S#state.generator, NewCount - Count) ++ S#state.nodes}};
63
+ NewCount < Count ->
64
+ {ToKill, ToKeep} = lists:split(NewCount - Count, S#state.nodes),
65
+ drop_nodes(S#state.terminator, ToKill),
66
+ {noreply, S#state{nodecount=NewCount, nodes=ToKeep}};
67
+ true ->
68
+ {noreply, S}
69
+ end.
70
+
71
+ handle_info({'EXIT', Pid, _Reason}, S) ->
72
+ Term = S#state.terminator,
73
+ Membership = lists:any(fun(X) -> X =:= Pid end, S#state.nodes),
74
+ if
75
+ Membership ->
76
+ Term(Pid),
77
+ Res = lists:delete(Pid, S#state.nodes),
78
+ NewNode = spawn_linked_node(S#state.generator),
79
+ {noreply, S#state{nodes=[NewNode|Res]}};
80
+ true ->
81
+ {noreply, S}
82
+ end;
83
+ handle_info(Any,S) ->
84
+ io:format("Got INFO ~p~n", [Any]),
85
+ {noreply, S}.
86
+
87
+ terminate(_Reason, _State) ->
88
+ ok.
89
+
90
+ code_change(_OldVsn, State, _Extra) ->
91
+ {ok, State}.
92
+
93
+ %% Utility functions
94
+
95
+ spawn_linked_node(Generator) ->
96
+ Node = Generator(),
97
+ link(Node),
98
+ Node.
99
+
100
+ spawn_nodes(Generator,NumNodes) ->
101
+ spawn_nodes(Generator,NumNodes,[]).
102
+
103
+ spawn_nodes(_Generator,0,Acc) -> Acc;
104
+ spawn_nodes(Generator,NumNodes,Acc) -> spawn_nodes(Generator,NumNodes - 1, [spawn_linked_node(Generator)|Acc]).
105
+
106
+ drop_nodes(Terminator, Nodes) ->
107
+ Killer = fun(Node) -> unlink(Node), Terminator(Node) end,
108
+ lists:map(Killer, Nodes).