File: rabbit_web_dispatch_sup.erl

package info (click to toggle)
rabbitmq-server 4.0.5-8
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 37,972 kB
  • sloc: erlang: 257,835; javascript: 22,466; sh: 3,037; makefile: 2,517; python: 1,966; xml: 646; cs: 335; java: 244; ruby: 212; php: 100; perl: 63; awk: 13
file content (127 lines) | stat: -rw-r--r-- 4,849 bytes parent folder | download | duplicates (2)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
%%
%% Copyright (c) 2007-2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
%%

-module(rabbit_web_dispatch_sup).

-behaviour(supervisor).

-define(SUP, ?MODULE).

%% External exports
-export([start_link/0, ensure_listener/1, stop_listener/1]).

%% supervisor callbacks
-export([init/1]).

%% @spec start_link() -> ServerRet
%% @doc API for starting the supervisor.
start_link() ->
    supervisor:start_link({local, ?SUP}, ?MODULE, []).

ensure_listener(Listener) ->
    case proplists:get_value(port, Listener) of
        undefined ->
            {error, {no_port_given, Listener}};
        _ ->
            {Transport, TransportOpts, ProtoOpts} = preprocess_config(Listener),
            ProtoOptsMap = maps:from_list(ProtoOpts),
            StreamHandlers = stream_handlers_config(ProtoOpts),
            rabbit_log:debug("Starting HTTP[S] listener with transport ~ts", [Transport]),
            CowboyOptsMap =
                maps:merge(#{env =>
                                #{rabbit_listener => Listener},
                             middlewares =>
                                [rabbit_cowboy_middleware, cowboy_router, cowboy_handler],
                             stream_handlers => StreamHandlers},
                           ProtoOptsMap),
            Child = ranch:child_spec(rabbit_networking:ranch_ref(Listener),
                Transport, TransportOpts,
                cowboy_clear, CowboyOptsMap),
            case supervisor:start_child(?SUP, Child) of
                {ok,                      _}  -> new;
                {error, {already_started, _}} -> existing;
                {error, {E, _}}               -> check_error(Listener, E)
            end
    end.

stop_listener(Listener) ->
    Name = rabbit_networking:ranch_ref(Listener),
    ok = supervisor:terminate_child(?SUP, {ranch_embedded_sup, Name}),
    ok = supervisor:delete_child(?SUP, {ranch_embedded_sup, Name}).

%% @spec init([[instance()]]) -> SupervisorTree
%% @doc supervisor callback.
init([]) ->
    Registry = {rabbit_web_dispatch_registry,
                {rabbit_web_dispatch_registry, start_link, []},
                transient, 5000, worker, [rabbit_web_dispatch_registry]},
    Log = {rabbit_mgmt_access_logger, {gen_event, start_link,
            [{local, webmachine_log_event}]},
           permanent, 5000, worker, dynamic},
    {ok, {{one_for_one, 10, 10}, [Registry, Log]}}.

%%
%% Implementation
%%

preprocess_config(Options) ->
    case proplists:get_value(ssl, Options) of
        true -> _ = rabbit_networking:ensure_ssl(),
                case proplists:get_value(ssl_opts, Options) of
                    undefined -> auto_ssl(Options);
                    _         -> fix_ssl(Options)
                end;
        _    -> {ranch_tcp, transport_config(Options), protocol_config(Options)}
    end.

auto_ssl(Options) ->
    {ok, ServerOpts} = application:get_env(rabbit, ssl_options),
    Remove = [verify, fail_if_no_peer_cert],
    SSLOpts = [{K, V} || {K, V} <- ServerOpts,
                         not lists:member(K, Remove)],
    fix_ssl([{ssl_opts, SSLOpts} | Options]).

fix_ssl(Options) ->
    SSLOpts = proplists:get_value(ssl_opts, Options),
    {ranch_ssl,
        transport_config(Options ++ rabbit_networking:fix_ssl_options(SSLOpts)),
        protocol_config(Options)}.

transport_config(Options0) ->
    Options = proplists:delete(protocol,
        proplists:delete(ssl,
        proplists:delete(ssl_opts,
            proplists:delete(cowboy_opts,
                Options0)))),
    case proplists:get_value(ip, Options) of
        undefined ->
            Options;
        IP when is_tuple(IP) ->
            Options;
        IP when is_list(IP) ->
            {ok, ParsedIP} = inet_parse:address(IP),
            [{ip, ParsedIP}|proplists:delete(ip, Options)]
    end.

protocol_config(Options) ->
    proplists:get_value(cowboy_opts, Options, []).

stream_handlers_config(Options) ->
    case lists:keyfind(compress, 1, Options) of
        {compress, false} -> [rabbit_cowboy_stream_h, cowboy_stream_h];
        %% Compress by default. Since 2.0 the compress option in cowboys
        %% has been replaced by the cowboy_compress_h handler
        %% Compress is not applied if data < 300 bytes
        _ -> [rabbit_cowboy_stream_h, cowboy_compress_h, cowboy_stream_h]
    end.

check_error(Listener, Error) ->
    Ignore = proplists:get_value(ignore_in_use, Listener, false),
    case {Error, Ignore} of
        {eaddrinuse, true} -> ignore;
        _                  -> exit({could_not_start_listener, Listener, Error})
    end.