Current section
Files
Jump to
Current section
Files
src/psl@suffix_list.erl
-module(psl@suffix_list).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/psl/suffix_list.gleam").
-export([find_suffix/2, parse/2, load/1]).
-export_type([suffix/0, suffix_list/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque suffix() :: {suffix, binary(), boolean(), integer()}.
-opaque suffix_list() :: {suffix_list,
gleam@dict:dict(binary(), suffix()),
list(binary()),
gleam@dict:dict(binary(), suffix())}.
-file("src/psl/suffix_list.gleam", 168).
?DOC(" Check if a suffix matches any wildcard pattern\n").
-spec check_wildcard_match(list(binary()), list(binary())) -> {ok, binary()} |
{error, nil}.
check_wildcard_match(Suffix_labels, Wildcards) ->
Normal_order = lists:reverse(Suffix_labels),
case Normal_order of
[] ->
{error, nil};
[_] ->
{error, nil};
[_ | Rest] ->
Parent = gleam@string:join(lists:reverse(Rest), <<"."/utf8>>),
case gleam@list:any(Wildcards, fun(W) -> W =:= Parent end) of
true ->
Matched = gleam@string:join(Normal_order, <<"."/utf8>>),
{ok, Matched};
false ->
{error, nil}
end
end.
-file("src/psl/suffix_list.gleam", 134).
?DOC(" Find all matching suffixes for the given labels\n").
-spec find_all_matches(list(binary()), suffix_list()) -> list(binary()).
find_all_matches(Labels, Suffix_list) ->
Reversed = lists:reverse(Labels),
_pipe = gleam@list:range(1, erlang:length(Labels)),
gleam@list:filter_map(
_pipe,
fun(I) ->
Suffix_labels = gleam@list:take(Reversed, I),
Suffix = begin
_pipe@1 = Suffix_labels,
_pipe@2 = lists:reverse(_pipe@1),
gleam@string:join(_pipe@2, <<"."/utf8>>)
end,
case gleam@dict:has_key(erlang:element(4, Suffix_list), Suffix) of
true ->
{error, nil};
false ->
case gleam@dict:has_key(
erlang:element(2, Suffix_list),
Suffix
) of
true ->
{ok, Suffix};
false ->
case check_wildcard_match(
Suffix_labels,
erlang:element(3, Suffix_list)
) of
{ok, Matched} ->
{ok, Matched};
{error, _} ->
{error, nil}
end
end
end
end
).
-file("src/psl/suffix_list.gleam", 115).
?DOC(" Find the matching public suffix for a hostname\n").
-spec find_suffix(binary(), suffix_list()) -> {ok, binary()} | {error, nil}.
find_suffix(Host, Suffix_list) ->
Labels = gleam@string:split(Host, <<"."/utf8>>),
Matches = find_all_matches(Labels, Suffix_list),
case Matches of
[] ->
{error, nil};
_ ->
_pipe = Matches,
_pipe@1 = gleam@list:sort(
_pipe,
fun(A, B) ->
gleam@int:compare(string:length(B), string:length(A))
end
),
_pipe@2 = gleam@list:first(_pipe@1),
gleam@result:replace_error(_pipe@2, nil)
end.
-file("src/psl/suffix_list.gleam", 85).
?DOC(" Add a single rule to the suffix list\n").
-spec add_rule(suffix_list(), binary(), boolean()) -> suffix_list().
add_rule(Sl, Rule, Is_public) ->
case gleam_stdlib:string_starts_with(Rule, <<"!"/utf8>>) of
true ->
Suffix_str = gleam@string:drop_start(Rule, 1),
Suffix = {suffix, Suffix_str, Is_public, string:length(Suffix_str)},
{suffix_list,
erlang:element(2, Sl),
erlang:element(3, Sl),
gleam@dict:insert(erlang:element(4, Sl), Suffix_str, Suffix)};
false ->
case gleam_stdlib:string_starts_with(Rule, <<"*"/utf8, "."/utf8>>) of
true ->
Pattern = gleam@string:drop_start(Rule, 2),
Suffix@1 = {suffix,
Pattern,
Is_public,
string:length(Pattern)},
{suffix_list,
gleam@dict:insert(
erlang:element(2, Sl),
Pattern,
Suffix@1
),
[Pattern | erlang:element(3, Sl)],
erlang:element(4, Sl)};
false ->
Suffix@2 = {suffix, Rule, Is_public, string:length(Rule)},
{suffix_list,
gleam@dict:insert(erlang:element(2, Sl), Rule, Suffix@2),
erlang:element(3, Sl),
erlang:element(4, Sl)}
end
end.
-file("src/psl/suffix_list.gleam", 42).
?DOC(" Parse the public suffix list content into a SuffixList\n").
-spec parse(binary(), boolean()) -> suffix_list().
parse(Content, Include_private) ->
Domain_data = case Include_private of
true ->
Content;
false ->
case gleam@string:split_once(
Content,
<<"===BEGIN PRIVATE DOMAINS==="/utf8>>
) of
{ok, {Public_domains, _}} ->
Public_domains;
{error, _} ->
Content
end
end,
{Suffix_list, _} = begin
_pipe = Domain_data,
_pipe@1 = gleam@string:split(_pipe, <<"\n"/utf8>>),
gleam@list:fold(
_pipe@1,
{{suffix_list, maps:new(), gleam@list:new(), maps:new()}, true},
fun(Acc, Line) ->
{Sl, Is_public} = Acc,
Trimmed = gleam@string:trim(Line),
case gleam_stdlib:contains_string(
Trimmed,
<<"===BEGIN PRIVATE DOMAINS==="/utf8>>
) of
true ->
case Include_private of
true ->
{Sl, false};
false ->
Acc
end;
false ->
case (Trimmed =:= <<""/utf8>>) orelse gleam_stdlib:string_starts_with(
Trimmed,
<<"//"/utf8>>
) of
true ->
Acc;
false ->
{add_rule(Sl, Trimmed, Is_public), Is_public}
end
end
end
)
end,
Suffix_list.
-file("src/psl/suffix_list.gleam", 35).
?DOC(" Load the public suffix list from the data file\n").
-spec load(boolean()) -> suffix_list().
load(Include_private) ->
Content@1 = case simplifile:read(<<"priv/public_suffix_list.dat"/utf8>>) of
{ok, Content} -> Content;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"psl/suffix_list"/utf8>>,
function => <<"load"/utf8>>,
line => 36,
value => _assert_fail,
start => 779,
'end' => 856,
pattern_start => 790,
pattern_end => 801})
end,
parse(Content@1, Include_private).