Skip to content

Commit

Permalink
Merge pull request #11 from esl/upgrades
Browse files Browse the repository at this point in the history
Upgrades
  • Loading branch information
DenysGonchar authored Jun 2, 2024
2 parents 14c5242 + 71053c1 commit 398e31a
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 38 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

[![Hex pm](http://img.shields.io/hexpm/v/mongoose_jid.svg?style=flat)](https://hex.pm/packages/mongoose_jid)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/mongoose_jid/)
[![Codecov](https://codecov.io/gh/esl/mongoose_jid/branch/master/graph/badge.svg)](https://codecov.io/gh/esl/mongoose_jid)
[![Downloads](https://img.shields.io/hexpm/dt/mongoose_jid.svg)](https://hex.pm/packages/mongoose_jid)
[![License](https://img.shields.io/hexpm/l/mongoose_jid.svg)](https://github.com/esl/mongoose_jid/blob/master/LICENSE)

An XMPP library for parsing JIDs, fully compliant with [RFC6122](https://datatracker.ietf.org/doc/html/rfc6122)

It offers functionality for parsing jids and turning them into jid records, normalising their parts or skipping normalisation when the input is trusted, and also to build binaries for the jid representation. It is highly performant, uses NIFs where it's best to, and has a wide API that can be consulted in the documentation.
It offers functionality for parsing jids and turning them into jid records, normalising their parts or skipping normalisation when the input is trusted, and also to build binaries for the jid representation. It is highly performant and widely documented.
5 changes: 2 additions & 3 deletions src/jid.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
{modules, []},
{maintainers, ["ESL"]},
{pkg_name, "mongoose_jid"},
{licenses, ["Apache 2.0"]},
{links, [{"GitHub", "https://github.com/esl/mongoose_jid/"}]},
{exclude_files, ["c_src/mongoose_jid.d"]}
{licenses, ["Apache-2.0"]},
{links, [{"GitHub", "https://github.com/esl/mongoose_jid/"}]}
]}.
39 changes: 30 additions & 9 deletions src/jid.erl
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@
-type lresource() :: binary().

-type jid() :: #jid{}.
%% JID data structure.
-type ljid() :: {luser(), lserver(), lresource()}.
%% 3-tuple containing the string-prepped binaries.
-type simple_jid() :: {user(), server(), resource()}.
%% 3-tuple containing not-yet string-prepped binaries.
-type simple_bare_jid() :: {luser(), lserver()}.
%% 2-tuple containing string-prepped user and server parts.
-type literal_jid() :: binary().
%% literal binary containing a bare or full JID, not ensured to be string-prepped.

-export_type([jid/0,
ljid/0,
Expand All @@ -40,9 +45,9 @@
% https://tools.ietf.org/html/rfc7622#section-3.1

%% @doc Takes the user, server, and resource parts, and returns a jid record or an error.
-spec make(User :: user(), Server :: server(), Res :: resource()) -> jid() | error.
make(User, Server, Res) ->
case {nodeprep(User), nameprep(Server), resourceprep(Res)} of
-spec make(User :: user(), Server :: server(), Resource :: resource()) -> jid() | error.
make(User, Server, Resource) ->
case {nodeprep(User), nameprep(Server), resourceprep(Resource)} of
{error, _, _} -> error;
{_, error, _} -> error;
{_, _, error} -> error;
Expand Down Expand Up @@ -160,7 +165,7 @@ from_binary_noprep(J) when is_binary(J), byte_size(J) < ?XMPP_JID_SIZE_LIMIT ->
from_binary_noprep(_) ->
error.

%% @doc Takes a representation of a jid, and outputs such jid as a literal binary
%% @doc Takes a representation of a jid, and outputs such jid as a literal binary.
-spec to_binary(simple_jid() | simple_bare_jid() | jid() | literal_jid()) -> binary().
to_binary({<<>>, Server, <<>>}) ->
Server;
Expand All @@ -179,17 +184,25 @@ to_binary(#jid{luser = LUser, lserver = LServer, lresource = LResource}) ->
to_binary(Jid) when is_binary(Jid) ->
Jid.

%% @doc Takes a representation of a jid, and outputs such jid as a literal binary in bare form.
-spec to_bare_binary(ljid() | simple_bare_jid() | jid() | literal_jid()) -> binary() | error.
to_bare_binary({<<>>, Server}) ->
<<Server/binary>>;
to_bare_binary({User, Server}) ->
<<User/binary, "@", Server/binary>>;
to_bare_binary({<<>>, Server, _}) ->
<<Server/binary>>;
to_bare_binary({User, Server, _}) ->
to_bare_binary({User, Server});
<<User/binary, "@", Server/binary>>;
to_bare_binary(#jid{luser = <<>>, lserver = LServer}) ->
<<LServer/binary>>;
to_bare_binary(#jid{luser = LUser, lserver = LServer}) ->
to_bare_binary({LUser, LServer});
to_bare_binary(Jid) when is_binary(Jid) ->
binary_to_bare(Jid).
<<LUser/binary, "@", LServer/binary>>;
to_bare_binary(BinJid) when is_binary(BinJid) ->
case binary_to_bare(BinJid) of
error -> error;
Jid -> to_binary(Jid)
end.

%% @doc Returns true if the input is a valid user part
-spec is_nodename(<<>> | binary()) -> boolean().
Expand All @@ -214,6 +227,7 @@ nodeprep(S) when is_binary(S), byte_size(S) < ?SANE_LIMIT ->
nodeprep(_) ->
error.

%% @doc Extract the string-prepped user part of the jid
-spec luser(jid() | ljid() | simple_bare_jid()) -> luser().
luser(#jid{luser = LUser}) ->
LUser;
Expand All @@ -222,6 +236,7 @@ luser({LUser, _, _}) ->
luser({LUser, _}) ->
LUser.

%% @doc Extract the string-prepped server part of the jid
-spec lserver(jid() | ljid() | simple_bare_jid()) -> lserver().
lserver(#jid{lserver = LServer}) ->
LServer;
Expand All @@ -230,6 +245,7 @@ lserver({_, LServer, _}) ->
lserver({_, LServer}) ->
LServer.

%% @doc Extract the string-prepped resource part of the jid
-spec lresource(jid() | ljid() | simple_bare_jid()) -> lresource().
lresource(#jid{lresource = LResource}) ->
LResource;
Expand Down Expand Up @@ -269,23 +285,28 @@ to_lower({U, S, R}) ->
end.

%% @doc Takes a jid and returns a prepared bare jid
-spec to_lus(jid() | ljid()) -> simple_bare_jid();
-spec to_lus(jid() | ljid() | simple_bare_jid()) -> simple_bare_jid();
(error) -> error.
to_lus(#jid{luser = U, lserver = S}) ->
{U, S};
to_lus({U, S, _}) ->
{U, S};
to_lus({U, S}) ->
{U, S};
to_lus(error) ->
error.

%% @doc Takes a jid and returns the same jid without its resourcepart
-spec to_bare(jid()) -> jid();
(ljid()) -> ljid();
(simple_bare_jid()) -> simple_bare_jid();
(error) -> error.
to_bare(#jid{} = JID) ->
JID#jid{lresource = <<>>};
to_bare({U, S, _R}) ->
{U, S, <<>>};
to_bare({U, S}) ->
{U, S};
to_bare(error) ->
error.

Expand Down
28 changes: 25 additions & 3 deletions test/jid_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ groups() ->
{common, [parallel],
[
empty_server_fails,
to_binary_with_binary_does_nothing,
to_binary_can_convert_all_types_of_jids,
binary_to_jid_succeeds_with_valid_binaries,
binary_to_jid_fails_with_invalid_binaries,
binary_to_jid_fails_with_empty_binary,
binary_noprep_to_jid_succeeds_with_valid_binaries,
binary_noprep_to_jid_fails_with_invalid_binaries,
binary_noprep_to_jid_fails_with_empty_binary,
make_jid_fails_on_binaries_that_are_too_long,
make_is_independent_of_the_input_format,
Expand All @@ -40,6 +43,7 @@ groups() ->
compare_bare_with_jids_structs_and_bare_jids,
binary_to_bare_equals_binary_and_then_bare,
to_bare_binary_equals_to_bare_then_to_binary,
to_bare_binary_fails_on_invalid_jids,
to_lower_to_bare_equals_to_bare_to_lower,
make_to_lus_equals_to_lower_to_lus,
make_bare_like_make_with_empty_resource,
Expand All @@ -61,12 +65,21 @@ end_per_suite(C) ->
empty_server_fails(_C) ->
?assertEqual(error, jid:from_binary(<<"$@/">>)).

to_binary_with_binary_does_nothing(_C) ->
Prop = ?FORALL(Bin, binary(),
Bin =:= jid:to_binary(Bin)),
run_property(Prop, 50, 1, 100).

to_binary_can_convert_all_types_of_jids(_C) ->
Prop = ?FORALL(BinJid, (jid_gen:jid_type()),
is_binary(jid:to_binary(BinJid))),
run_property(Prop, 200, 1, 100).

binary_to_jid_succeeds_with_valid_binaries(_C) ->
Prop = ?FORALL(BinJid, (jid_gen:jid()),
(is_record(jid:from_binary(BinJid), jid))),
run_property(Prop, 200, 1, 100).


binary_to_jid_fails_with_invalid_binaries(_C) ->
Prop = ?FORALL(BinJid, jid_gen:invalid_jid(),
error == jid:from_binary(BinJid)),
Expand All @@ -80,8 +93,13 @@ binary_noprep_to_jid_succeeds_with_valid_binaries(_) ->
(is_record(jid:from_binary_noprep(BinJid), jid))),
run_property(Prop, 200, 1, 100).

binary_noprep_to_jid_fails_with_invalid_binaries(_C) ->
Prop = ?FORALL(Bin, jid_gen:jid(),
error == jid:from_binary_noprep(Bin)),
run_property(Prop, 5, 3071, 5048).

binary_noprep_to_jid_fails_with_empty_binary(_) ->
error = jid:from_binary(<<>>).
error = jid:from_binary_noprep(<<>>).

make_jid_fails_on_binaries_that_are_too_long(_) ->
Prop = ?FORALL({U, S, R},
Expand Down Expand Up @@ -235,10 +253,14 @@ binary_to_bare_equals_binary_and_then_bare(_) ->
run_property(Prop, 200, 1, 100).

to_bare_binary_equals_to_bare_then_to_binary(_) ->
Prop = ?FORALL(A, jid_gen:jid_struct(),
Prop = ?FORALL(A, jid_gen:jid_type(),
equals(jid:to_binary(jid:to_bare(A)), jid:to_bare_binary(A))),
run_property(Prop, 200, 1, 100).

to_bare_binary_fails_on_invalid_jids(_) ->
?assertEqual(<<"a@a">>, jid:to_bare_binary(<<"a@a/a">>)),
?assertEqual(error, jid:to_bare_binary(<<"aa@/aa">>)).

to_lower_to_bare_equals_to_bare_to_lower(_) ->
Prop = ?FORALL(JID, oneof([jid_gen:jid_struct(),
{jid_gen:maybe_valid_username(),
Expand Down
52 changes: 30 additions & 22 deletions test/jid_gen.erl
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
-module(jid_gen).

-export([jid_struct/0]).
-export([from_jid/0]).
-export([jid/0]).
-export([bare_jid/0]).
-export([full_jid/0]).
-export([username/0]).
-export([domain/0]).
-export([resource/0]).
-export([maybe_valid_jid/0]).
-export([invalid_jid/0]).
-export([invalid_bare_jid/0]).
-export([invalid_full_jid/0]).
-export([maybe_valid_username/0]).
-export([invalid_username/0]).
-export([maybe_valid_domain/0]).
-export([invalid_domain/0]).
-export([maybe_valid_resource/0]).
-export([invalid_resource/0]).
-compile([export_all, nowarn_export_all]).

-include_lib("proper/include/proper.hrl").

jid_type() ->
oneof([jid_struct(), ljid_struct(), simple_bare_jid_struct()]).

jid_struct() ->
?LET({U, S, R}, {username(), domain(), resource()},
{jid, U, S, R}).
oneof([
?LET({U, S, R}, {username(), domain(), resource()}, {jid, U, S, R}),
?LET({U, S}, {username(), domain()}, {jid, U, S, <<>>}),
?LET({U, S, R}, {username(), domain(), resource()}, {jid, U, S, R}),
?LET({S, R}, {domain(), resource()}, {jid, <<>>, S, R}),
?LET(S, domain(), {jid, <<>>, S, <<>>})
]).

ljid_struct() ->
oneof([
?LET({U, S, R}, {username(), domain(), resource()}, {U, S, R}),
?LET({U, S}, {username(), domain()}, {U, S, <<>>}),
?LET({U, S, R}, {username(), domain(), resource()}, {U, S, R}),
?LET({S, R}, {domain(), resource()}, {<<>>, S, R})
]).

simple_bare_jid_struct() ->
oneof([
?LET({U, S}, {username(), domain()}, {U, S}),
?LET(S, domain(), {<<>>, S})
]).

from_jid() ->
oneof([
Expand All @@ -34,7 +38,7 @@ from_jid() ->
]).

jid() ->
oneof([full_jid(), bare_jid(), domain()]).
oneof([full_jid(), bare_jid(), domain(), service()]).

bare_jid() ->
?LET({Username, Domain}, {username(), domain()},
Expand All @@ -50,6 +54,10 @@ username() ->
domain() ->
?SIZED(S, always_correct_xmpp_binary(round(S*1.5))).

service() ->
?LET({Domain, Resource}, {domain(), resource()},
<<Domain/binary, $/, Resource/binary>>).

resource() ->
?SIZED(S, always_correct_xmpp_binary(round(S*1.7))).

Expand Down

0 comments on commit 398e31a

Please sign in to comment.