• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supavisor / 19911268462

03 Dec 2025 10:43PM UTC coverage: 63.801% (-0.2%) from 63.971%
19911268462

push

github

web-flow
chore: more buckets for higher resolution on histograms (#784)

1870 of 2931 relevant lines covered (63.8%)

4193.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.83
/lib/supavisor/handler_helpers.ex
1
defmodule Supavisor.HandlerHelpers do
2
  @moduledoc false
3

4
  require Supavisor.Protocol.Server, as: Server
5

6
  @spec sock_send(Supavisor.sock(), iodata()) :: :ok | {:error, term()}
7
  def sock_send({mod, sock}, data) do
8
    mod.send(sock, data)
29,222✔
9
  end
10

11
  @spec sock_close(Supavisor.sock() | nil | {any(), nil}) :: :ok | {:error, term()}
12
  def sock_close(nil), do: :ok
×
13
  def sock_close({_, nil}), do: :ok
×
14

15
  def sock_close({mod, sock}), do: mod.close(sock)
254✔
16

17
  @spec setopts(Supavisor.sock(), term()) :: :ok | {:error, term()}
18
  def setopts({mod, sock}, opts) do
19
    mod = if mod == :gen_tcp, do: :inet, else: mod
6,448✔
20
    mod.setopts(sock, opts)
6,448✔
21
  end
22

23
  @spec active_once(Supavisor.sock()) :: :ok | {:error, term}
24
  def active_once(sock), do: setopts(sock, active: :once)
×
25

26
  @spec activate(Supavisor.sock()) :: :ok | {:error, term}
27
  def activate(sock), do: setopts(sock, active: true)
6,325✔
28

29
  @spec try_ssl_handshake(Supavisor.tcp_sock(), boolean) ::
30
          {:ok, Supavisor.sock()} | {:error, term()}
31
  def try_ssl_handshake(sock, true) do
32
    case sock_send(sock, Server.ssl_request()) do
×
33
      :ok -> ssl_recv(sock)
×
34
      error -> error
×
35
    end
36
  end
37

38
  def try_ssl_handshake(sock, false), do: {:ok, sock}
×
39

40
  @spec ssl_recv(Supavisor.tcp_sock()) :: {:ok, Supavisor.ssl_sock()} | {:error, term}
41
  def ssl_recv({:gen_tcp, sock} = s) do
42
    case :gen_tcp.recv(sock, 1, 15_000) do
×
43
      {:ok, <<?S>>} -> ssl_connect(s)
×
44
      {:ok, <<?N>>} -> {:ok, s}
×
45
      {:error, _} = error -> error
×
46
    end
47
  end
48

49
  @spec ssl_connect(Supavisor.tcp_sock(), pos_integer) ::
50
          {:ok, Supavisor.ssl_sock()} | {:error, term}
51
  def ssl_connect({:gen_tcp, sock}, timeout \\ 5000) do
52
    opts = [verify: :verify_none]
×
53

54
    case :ssl.connect(sock, opts, timeout) do
×
55
      {:ok, ssl_sock} -> {:ok, {:ssl, ssl_sock}}
×
56
      {:error, reason} -> {:error, reason}
×
57
    end
58
  end
59

60
  @spec send_error(Supavisor.sock(), String.t(), String.t()) :: :ok | {:error, term()}
61
  def send_error(sock, code, message) do
62
    data = Server.error_message(code, message)
×
63
    sock_send(sock, data)
×
64
  end
65

66
  @spec try_get_sni(Supavisor.sock()) :: String.t() | nil
67
  def try_get_sni({:ssl, sock}) do
68
    case :ssl.connection_information(sock, [:sni_hostname]) do
1✔
69
      {:ok, [sni_hostname: sni]} -> List.to_string(sni)
×
70
      _ -> nil
1✔
71
    end
72
  end
73

74
  def try_get_sni(_), do: nil
592✔
75

76
  @spec reset_active_count(%{sock: Supavisor.sock()}) :: 0
77
  def reset_active_count(%{sock: sock}) do
78
    activate(sock)
×
79
    0
80
  end
81

82
  @spec parse_user_info(map) ::
83
          {:cluster | :single, {String.t() | nil, String.t(), String.t() | nil}}
84
  def parse_user_info(%{"user" => user, "options" => %{"reference" => ref}} = payload) do
1✔
85
    # TODO: parse ref for cluster
86
    {:single, {user, ref, payload["database"]}}
87
  end
88

89
  def parse_user_info(%{"user" => user} = payload) do
90
    db_name = payload["database"]
600✔
91

92
    case :binary.split(user, ".cluster.") do
600✔
93
      [user] ->
94
        case :binary.matches(user, ".") do
599✔
95
          [] ->
3✔
96
            {:single, {user, nil, db_name}}
97

98
          matches ->
99
            {pos, 1} = List.last(matches)
596✔
100
            <<name::size(pos)-binary, ?., external_id::binary>> = user
596✔
101
            {:single, {name, external_id, db_name}}
102
        end
103

104
      [user, tenant] ->
1✔
105
        {:cluster, {user, tenant, db_name}}
106
    end
107
  end
108

109
  @doc """
110
  Takes an allow list of CIDR ranges and filtres them for ranges which contain the address
111
  to test.
112

113
  If the IP address of the socket is not found an empty list is returned.
114

115
  ## Examples
116

117
    iex> Supavisor.HandlerHelpers.filter_cidrs(["0.0.0.0/0", "::/0"], {127, 0, 0, 1})
118
    ["0.0.0.0/0"]
119

120
    iex> Supavisor.HandlerHelpers.filter_cidrs(["71.209.249.38/32"], {71, 209, 249, 39})
121
    []
122

123
    iex> Supavisor.HandlerHelpers.filter_cidrs(["0.0.0.0/0", "::/0"], {8193, 3512, 34211, 0, 0, 35374, 880, 29492})
124
    ["::/0"]
125

126
    iex> Supavisor.HandlerHelpers.filter_cidrs(["0.0.0.0/0", "::/0"], :error)
127
    []
128

129
  """
130

131
  @spec filter_cidrs(list(), :inet.ip_address() | any()) :: list()
132
  def filter_cidrs(allow_list, addr) when is_list(allow_list) and is_tuple(addr) do
133
    for range <- allow_list,
596✔
134
        range |> InetCidr.parse_cidr!() |> InetCidr.contains?(addr) do
135
      range
136
    end
137
  end
138

139
  def filter_cidrs(allow_list, _addr) when is_list(allow_list) do
1✔
140
    []
141
  end
142

143
  @spec addr_from_sock(Supavisor.sock()) :: {:ok, :inet.ip_address()} | :error
144
  def addr_from_sock({:gen_tcp, port}) do
145
    case :inet.peername(port) do
592✔
146
      {:ok, {:local, _}} ->
×
147
        :error
148

149
      {:ok, {:undefined, _}} ->
×
150
        :error
151

152
      {:ok, {:unspec, _}} ->
×
153
        :error
154

155
      {:ok, {addr, _port}} ->
592✔
156
        {:ok, addr}
157

158
      {:error, _} ->
×
159
        :error
160
    end
161
  end
162

163
  def addr_from_sock({:ssl, port}) do
164
    case :ssl.peername(port) do
1✔
165
      {:ok, {addr, _port}} ->
1✔
166
        {:ok, addr}
167

168
      {:error, _} ->
×
169
        :error
170
    end
171
  end
172
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc