Skip to content

Commit 95a96b3

Browse files
authored
Merge pull request #249 from hmmr/azavada/develop-3.0/fqdn-datatype
new fqdn datatype
2 parents e84070b + e9069c1 commit 95a96b3

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

src/cuttlefish_datatypes.erl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
{flag, {atom(), term()}, {atom(), term()}} |
3636
{enum, [atom()]} |
3737
ip |
38+
fqdn |
3839
{duration, cuttlefish_duration:time_unit() } |
3940
bytesize |
4041
{percent, integer} |
@@ -75,6 +76,7 @@ is_supported({flag, {On, _}, {Off, _}}) when is_atom(On), is_atom(Off) -> true;
7576
is_supported(atom) -> true;
7677
is_supported({enum, E}) when is_list(E) -> true;
7778
is_supported(ip) -> true;
79+
is_supported(fqdn) -> true;
7880
is_supported({duration, f}) -> true;
7981
is_supported({duration, w}) -> true;
8082
is_supported({duration, d}) -> true;
@@ -96,6 +98,8 @@ is_extended({file, F}) when is_list(F) -> true;
9698
is_extended({directory, D}) when is_list(D) -> true;
9799
is_extended({ip, {IP, Port}}) when is_list(IP) andalso is_integer(Port) -> true;
98100
is_extended({ip, StringIP}) when is_list(StringIP) -> true;
101+
is_extended({fqdn, {FQDN, Port}}) when is_list(FQDN) andalso is_integer(Port) -> true;
102+
is_extended({fqdn, StringFQDN}) when is_list(StringFQDN) -> true;
99103
is_extended({{duration, f}, D}) when is_list(D) -> true;
100104
is_extended({{duration, w}, D}) when is_list(D) -> true;
101105
is_extended({{duration, d}, D}) when is_list(D) -> true;
@@ -116,6 +120,7 @@ extended_from({atom, _}) -> atom;
116120
extended_from({file, _}) -> file;
117121
extended_from({directory, _}) -> directory;
118122
extended_from({ip, _}) -> ip;
123+
extended_from({fqdn, _}) -> fqdn;
119124
extended_from({{duration, Unit}, _}) -> {duration, Unit};
120125
extended_from({bytesize, _}) -> bytesize;
121126
extended_from({{percent, integer}, _}) -> {percent, integer};
@@ -149,6 +154,9 @@ to_string(Integer, integer) when is_list(Integer) -> Integer;
149154
to_string({IP, Port}, ip) when is_list(IP), is_integer(Port) -> IP ++ ":" ++ integer_to_list(Port);
150155
to_string(IPString, ip) when is_list(IPString) -> IPString;
151156

157+
to_string({FQDN, Port}, fqdn) when is_list(FQDN), is_integer(Port) -> FQDN ++ ":" ++ integer_to_list(Port);
158+
to_string(FQDNString, fqdn) when is_list(FQDNString) -> FQDNString;
159+
152160
to_string(Enum, {enum, _}) when is_list(Enum) -> Enum;
153161
to_string(Enum, {enum, _}) when is_atom(Enum) -> atom_to_list(Enum);
154162

@@ -211,6 +219,10 @@ from_string({IP, Port}, ip) when is_list(IP), is_integer(Port) -> {IP, Port};
211219
from_string(String, ip) when is_list(String) ->
212220
from_string_to_ip(String, lists:split(string:rchr(String, $:), String));
213221

222+
from_string({FQDN, Port}, fqdn) when is_list(FQDN), is_integer(Port) -> {FQDN, Port};
223+
from_string(String, fqdn) when is_list(String) ->
224+
from_string_to_fqdn(String, lists:split(string:rchr(String, $:), String));
225+
214226
from_string(Duration, {duration, _}) when is_integer(Duration) -> Duration;
215227
from_string(Duration, {duration, Unit}) when is_list(Duration) -> cuttlefish_duration:parse(Duration, Unit);
216228

@@ -282,6 +294,17 @@ ip_conversions(String, _IPStr, _IP, undefined) ->
282294
ip_conversions(_String, IPStr, {ok, _}, Port) ->
283295
{IPStr, Port}.
284296

297+
fqdn_conversions(String, _FQDNStr, nomatch, _Port) ->
298+
{error, {conversion, {String, 'FQDN'}}};
299+
fqdn_conversions(String, _FQDNStr, _, undefined) ->
300+
{error, {conversion, {String, 'FQDN'}}};
301+
fqdn_conversions(_String, FQDNStr, {match, _}, Port) ->
302+
{FQDNStr, Port}.
303+
304+
validate_fqdn(Str) ->
305+
%% inspired by https://regexr.com/3g5j0, amended to disallow [:space:]
306+
re:run(Str, "^(?!:\/\/)(?=[^[:space:]]{1,255}$)((.{1,63}\.){1,127}(?![0-9]*$)[a-z0-9-]+\.?)$").
307+
285308
droplast(List) ->
286309
lists:sublist(List, length(List)-1).
287310

@@ -294,6 +317,12 @@ from_string_to_ip(String, {IpPlusColon, PortString}) ->
294317
IP = droplast(IpPlusColon),
295318
ip_conversions(String, IP, inet:parse_address(IP), port_to_integer(PortString)).
296319

320+
from_string_to_fqdn(String, {[], String}) ->
321+
{error, {conversion, {String, 'FQDN'}}};
322+
from_string_to_fqdn(String, {FQDNPlusColon, PortString}) ->
323+
FQDN = droplast(FQDNPlusColon),
324+
fqdn_conversions(String, FQDN, validate_fqdn(FQDN), port_to_integer(PortString)).
325+
297326

298327
-ifdef(TEST).
299328

@@ -348,6 +377,8 @@ to_string_extended_type_test() ->
348377
?assertEqual("32", to_string("32", {integer, 32})),
349378
?assertEqual("127.0.0.1:8098", to_string("127.0.0.1:8098", {ip, "127.0.0.1:8098"})),
350379
?assertEqual("127.0.0.1:8098", to_string({"127.0.0.1", 8098}, {ip, {"127.0.0.1", 8098}})),
380+
?assertEqual("example.com:8098", to_string("example.com:8098", {fqdn, "example.com:8098"})),
381+
?assertEqual("example.com:8098", to_string({"example.com", 8098}, {fqdn, {"example.com", 8098}})),
351382
?assertEqual("string", to_string("string", {string, "string"})),
352383
?assertEqual("1w", to_string("1w", {{duration, s}, "1w"})),
353384
?assertEqual("1w", to_string(604800000, {{duration, ms}, "1w"})),
@@ -405,6 +436,38 @@ from_string_ip_test() ->
405436
BadIPs),
406437
ok.
407438

439+
from_string_fqdn_test() ->
440+
?assertEqual({"fqdn.com", 8098}, from_string("fqdn.com:8098", fqdn)),
441+
?assertEqual(
442+
{"f.q.d.n.com", 8098},
443+
from_string("f.q.d.n.com:8098", fqdn)),
444+
?assertEqual(
445+
{"fqdn.com.", 8098},
446+
from_string("fqdn.com.:8098", fqdn)),
447+
?assertEqual(
448+
{"FqDn.com", 8098},
449+
from_string("FqDn.com:8098", fqdn)),
450+
?assertEqual(
451+
{"ec2-35-160-210-253.us-west-2-.compute.amazonaws.com", 1},
452+
from_string("ec2-35-160-210-253.us-west-2-.compute.amazonaws.com:1", fqdn)),
453+
454+
BadFQDNs = [
455+
"This is not an fqdn:80",
456+
"This.is not.an.fqdn:80",
457+
"",
458+
"127.0.0.1:80",
459+
"fqdn.com", %% No port
460+
"fqdn.com:-5",
461+
"fqdn.com:80:81"
462+
],
463+
464+
lists:foreach(fun(Bad) ->
465+
?assertEqual({error, {conversion, {Bad, 'FQDN'}}},
466+
from_string(Bad, fqdn))
467+
end,
468+
BadFQDNs),
469+
ok.
470+
408471
from_string_enum_test() ->
409472
?assertEqual("\"a\" is not a valid enum value, acceptable values are: b, c", ?XLATE(from_string(a, {enum, [b, c]}))),
410473
?assertEqual(true, from_string("true", {enum, [true, false]})),

0 commit comments

Comments
 (0)