summaryrefslogtreecommitdiff
path: root/src/chttpd/src/chttpd_handlers.erl
blob: d46875d75f2e9522189540dbe5d9510136cbb27e (plain)
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
105
106
107
108
109
110
111
112
113
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License.  You may obtain a copy of
% the License at
%
%   http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
% License for the specific language governing permissions and limitations under
% the License.

-module(chttpd_handlers).

-export([
    url_handler/2,
    db_handler/2,
    design_handler/2,
    handler_info/1
]).

-define(SERVICE_ID, chttpd_handlers).

-include_lib("couch/include/couch_db.hrl").
-include_lib("kernel/include/logger.hrl").

%% ------------------------------------------------------------------
%% API Function Definitions
%% ------------------------------------------------------------------

url_handler(HandlerKey, DefaultFun) ->
    select(collect(url_handler, [HandlerKey]), DefaultFun).

db_handler(HandlerKey, DefaultFun) ->
    select(collect(db_handler, [HandlerKey]), DefaultFun).

design_handler(HandlerKey, DefaultFun) ->
    select(collect(design_handler, [HandlerKey]), DefaultFun).

handler_info(HttpReq) ->
    #httpd{
        method = Method,
        path_parts = PathParts
    } = HttpReq,
    Default = {'unknown.unknown', #{}},
    try
        select(collect(handler_info, [Method, PathParts, HttpReq]), Default)
    catch Type:Reason:Stack ->
        ?LOG_ERROR(#{
            what => handler_info_failure,
            result => Type,
            details => Reason,
            stack => Stack
        }),
        couch_log:error("~s :: handler_info failure for ~p : ~p:~p :: ~p", [
                ?MODULE,
                get(nonce),
                Type,
                Reason,
                Stack
            ]),
        Default
    end.

%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------

collect(Func, Args) ->
    Results = do_apply(Func, Args, []),
    [HandlerFun || HandlerFun <- Results, HandlerFun /= no_match].

do_apply(Func, Args, Opts) ->
    Handle = couch_epi:get_handle(?SERVICE_ID),
    couch_epi:apply(Handle, ?SERVICE_ID, Func, Args, Opts).

select([], Default) ->
    Default;
select([{default, OverrideDefault}], _Default) ->
    OverrideDefault;
select(Handlers, _Default) ->
    [Handler] = do_select(Handlers, []),
    Handler.

do_select([], Acc) ->
    Acc;
do_select([{override, Handler}|_], _Acc) ->
    [Handler];
do_select([{default, _}|Rest], Acc) ->
    do_select(Rest, Acc);
do_select([Handler], Acc) ->
    [Handler | Acc];
do_select([Handler | Rest], Acc) ->
    do_select(Rest, [Handler | Acc]).

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").

select_override_test() ->
    ?assertEqual(selected, select([{override, selected}, foo], default)),
    ?assertEqual(selected, select([foo, {override, selected}], default)),
    ?assertEqual(selected, select([{override, selected}, {override, bar}], default)),
    ?assertError({badmatch,[bar, foo]}, select([foo, bar], default)).

select_default_override_test() ->
    ?assertEqual(selected, select([{default, new_default}, selected], old_default)),
    ?assertEqual(selected, select([selected, {default, new_default}], old_default)),
    ?assertEqual(selected, select([{default, selected}], old_default)),
    ?assertEqual(selected, select([], selected)),
    ?assertEqual(selected,
        select([{default, new_default}, {override, selected}, bar], old_default)).

-endif.