1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
%%% Copyright (c) 2014-2016, NORDUnet A/S.
%%% See LICENSE for licensing information.
-module(catlfish_web).
-export([start/3, loop/2]).
start(Options, Module, Name) ->
lager:debug("Starting catlfish web server: ~p", [Module]),
Loop = fun (Req) ->
?MODULE:loop(Req, Module)
end,
mochiweb_http:start([{name, Name}, {loop, Loop} | Options]).
add_auth(Path, {Code, Headers, Data}) ->
AuthHeader = http_auth:create_auth("REPLY", Path, Data),
lager:debug("sent auth header: ~p", [AuthHeader]),
{Code, [{"X-Catlfish-Auth", AuthHeader} | Headers], Data}.
split_path([]) ->
{[], []};
split_path([E]) ->
{E, []};
split_path(Parts) ->
[Fun | AppRev] = lists:reverse(Parts),
App = string:join(lists:reverse(AppRev), "/"),
{Fun, App}.
loop(Req, Module) ->
Path = Req:get(path),
{Fun, App} = split_path(string:tokens(Path, "/")),
lager:debug("Fun=~s; App=~s;", [Fun, App]),
try
Starttime = os:timestamp(),
AuthHeader = Req:get_header_value("X-Catlfish-Auth"),
case Req:get(method) of
'GET' ->
Query = Req:parse_qs(),
{_, RawQuery, _} = mochiweb_util:urlsplit_path(Req:get(raw_path)),
Result = case http_auth:verify_auth(AuthHeader, "GET",
Path, RawQuery) of
failure ->
{403, [{"Content-Type", "text/plain"}],
"Invalid credentials"};
success ->
lager:info("GET ~p", [Path]),
lager:debug("GET ~p ~p", [Path, Query]),
add_auth(Path,
Module:request(get, App, Fun, Query));
noauth ->
lager:info("GET ~p", [Path]),
lager:debug("GET ~p ~p", [Path, Query]),
Module:request(get, App, Fun, Query)
end,
lager:info("GET finished: ~p us",
[timer:now_diff(os:timestamp(), Starttime)]),
case Result of
none ->
Req:respond({404, [{"Content-Type", "text/plain"}],
"Page not found"});
_ ->
Req:respond(Result)
end;
'POST' ->
Body = Req:recv_body(),
Result = case http_auth:verify_auth(AuthHeader, "POST",
Path, Body) of
failure ->
{403, [{"Content-Type", "text/plain"}],
"Invalid credentials"};
success ->
lager:info("POST ~p", [Path]),
lager:debug("POST ~p ~p", [Path, Body]),
add_auth(Path,
Module:request(post, App, Fun, Body));
noauth ->
lager:info("POST ~p", [Path]),
lager:debug("POST ~p ~p", [Path, Body]),
Module:request(post, App, Fun, Body)
end,
lager:info("POST finished: ~p us",
[timer:now_diff(os:timestamp(), Starttime)]),
case Result of
none ->
Req:respond({404, [{"Content-Type", "text/plain"}],
"Page not found"});
_ ->
Req:respond(Result)
end;
_ ->
Req:respond({501, [], []})
end
catch
exit:{body_too_large, What} ->
lager:info("HTTP POST body too large: ~p", [What]),
Req:respond({413, [{"Content-Type", "text/plain"}],
"Request Entity Too Large\n"});
Type:What ->
[CrashFunction | Stack] = erlang:get_stacktrace(),
lager:error("Crash in ~p for path ~p: ~p ~p~n~p~n~p~n",
[Module, Path, Type, What, CrashFunction, Stack]),
Req:respond({500, [{"Content-Type", "text/plain"}],
"Internal Server Error\n"})
end.
|