From 92840edafdad8cba39f646928691fb318451841e Mon Sep 17 00:00:00 2001 From: Michael Weibel Date: Tue, 13 Jan 2015 08:23:56 +0100 Subject: [PATCH] Use erlang-idna from hackney instead of own impl. Removes maintenance burden of `idna` and also enables the use of `hackney` when developing own modules (otherwise there's a conflict because both modules are called the same). --- apps/ejabberd/src/ejabberd_s2s.erl | 16 +- apps/ejabberd/src/ejabberd_s2s_in.erl | 4 +- apps/ejabberd/src/ejabberd_s2s_out.erl | 2 +- apps/ejabberd/src/idna.erl | 218 ------------------------- rebar.config | 1 + rel/reltool.config.script | 3 +- 6 files changed, 21 insertions(+), 223 deletions(-) delete mode 100644 apps/ejabberd/src/idna.erl diff --git a/apps/ejabberd/src/ejabberd_s2s.erl b/apps/ejabberd/src/ejabberd_s2s.erl index 81649de2980..3fed04d7524 100644 --- a/apps/ejabberd/src/ejabberd_s2s.erl +++ b/apps/ejabberd/src/ejabberd_s2s.erl @@ -41,7 +41,8 @@ dirty_get_connections/0, allow_host/2, incoming_s2s_number/0, - outgoing_s2s_number/0 + outgoing_s2s_number/0, + domain_utf8_to_ascii/1 ]). %% gen_server callbacks @@ -463,6 +464,19 @@ parent_domains(<<_, Rest/binary>>, Acc) -> send_element(Pid, El) -> Pid ! {send_element, El}. +%%-------------------------------------------------------------------- +%% Function: domain_utf8_to_ascii(Domain) -> binary() | false +%% Description: Converts a UTF-8 domain to ASCII (IDNA) +%% -------------------------------------------------------------------- +-spec domain_utf8_to_ascii(binary() | string()) -> binary() | false. +domain_utf8_to_ascii(Domain) -> + case catch idna:utf8_to_ascii(Domain) of + {'EXIT', _} -> + false; + AsciiDomain -> + list_to_binary(AsciiDomain) + end. + %%%---------------------------------------------------------------------- %%% ejabberd commands diff --git a/apps/ejabberd/src/ejabberd_s2s_in.erl b/apps/ejabberd/src/ejabberd_s2s_in.erl index c746587c1cf..045cdc063bb 100644 --- a/apps/ejabberd/src/ejabberd_s2s_in.erl +++ b/apps/ejabberd/src/ejabberd_s2s_in.erl @@ -332,7 +332,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> error -> false; _ -> - case idna:domain_utf8_to_ascii(AuthDomain) of + case ejabberd_s2s:domain_utf8_to_ascii(AuthDomain) of false -> false; PCAuthDomain -> @@ -757,7 +757,7 @@ get_cert_domains(Cert) -> #jid{luser = <<"">>, lserver = LD, lresource = <<"">>} -> - case idna:domain_utf8_to_ascii(LD) of + case ejabberd_s2s:domain_utf8_to_ascii(LD) of false -> []; PCLD -> diff --git a/apps/ejabberd/src/ejabberd_s2s_out.erl b/apps/ejabberd/src/ejabberd_s2s_out.erl index 0eaf5bd8038..fc4ca0910c9 100644 --- a/apps/ejabberd/src/ejabberd_s2s_out.erl +++ b/apps/ejabberd/src/ejabberd_s2s_out.erl @@ -232,7 +232,7 @@ open_socket(init, StateData) -> StateData#state.new, StateData#state.verify}]), AddrList = get_predefined_addresses(StateData#state.server) ++ - case idna:domain_utf8_to_ascii(StateData#state.server) of + case ejabberd_s2s:domain_utf8_to_ascii(StateData#state.server) of false -> []; ASCIIAddr -> diff --git a/apps/ejabberd/src/idna.erl b/apps/ejabberd/src/idna.erl deleted file mode 100644 index bb934bf215e..00000000000 --- a/apps/ejabberd/src/idna.erl +++ /dev/null @@ -1,218 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : idna.erl -%%% Author : Alexey Shchepin -%%% Purpose : Support for IDNA (RFC3490) -%%% Created : 10 Apr 2004 by Alexey Shchepin -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2011 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License -%%% along with this program; if not, write to the Free Software -%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA -%%% -%%%---------------------------------------------------------------------- - --module(idna). --author('alexey@process-one.net'). - -%%-compile(export_all). --export([domain_utf8_to_ascii/1]). - -%% @doc TODO: Ugly, need to provide separate functions -%% TODO: for binaries or convert whole module --spec domain_utf8_to_ascii(binary() | string()) -> string(). -domain_utf8_to_ascii(Domain) when is_binary(Domain) -> - list_to_binary(domain_utf8_to_ascii(binary_to_list(Domain))); -domain_utf8_to_ascii(Domain) -> - domain_ucs2_to_ascii(utf8_to_ucs2(Domain)). - - --spec utf8_to_ucs2(string()) -> string(). -utf8_to_ucs2(S) -> - utf8_to_ucs2(S, ""). - - --spec utf8_to_ucs2(string(), string()) -> string(). -utf8_to_ucs2([], R) -> - lists:reverse(R); -utf8_to_ucs2([C | S], R) when C < 16#80 -> - utf8_to_ucs2(S, [C | R]); -utf8_to_ucs2([C1, C2 | S], R) when C1 < 16#E0 -> - utf8_to_ucs2(S, [((C1 band 16#1F) bsl 6) bor - (C2 band 16#3F) | R]); -utf8_to_ucs2([C1, C2, C3 | S], R) when C1 < 16#F0 -> - utf8_to_ucs2(S, [((C1 band 16#0F) bsl 12) bor - ((C2 band 16#3F) bsl 6) bor - (C3 band 16#3F) | R]). - - --spec domain_ucs2_to_ascii(string()) -> string() | false. -domain_ucs2_to_ascii(Domain) -> - case catch domain_ucs2_to_ascii1(Domain) of - {'EXIT', _Reason} -> - false; - Res -> - Res - end. - - --spec domain_ucs2_to_ascii1(string()) -> string(). -domain_ucs2_to_ascii1(Domain) -> - Parts = string:tokens(Domain, [16#002E, 16#3002, 16#FF0E, 16#FF61]), - ASCIIParts = lists:map(fun(P) -> - to_ascii(P) - end, Parts), - string:strip(lists:flatmap(fun(P) -> [$. | P] end, ASCIIParts), - left, $.). - -%% @doc Domain names are already nameprep'ed in ejabberd, so we skiping this step --spec to_ascii(nonempty_string()) -> nonempty_string(). -to_ascii(Name) -> - false = lists:any( - fun(C) when - ( 0 =< C) and (C =< 16#2C) or - (16#2E =< C) and (C =< 16#2F) or - (16#3A =< C) and (C =< 16#40) or - (16#5B =< C) and (C =< 16#60) or - (16#7B =< C) and (C =< 16#7F) -> - true; - (_) -> - false - end, Name), - case Name of - [H | _] when H /= $- -> - true = lists:last(Name) /= $- - end, - ASCIIName = case lists:any(fun(C) -> C > 16#7F end, Name) of - true -> - true = case Name of - "xn--" ++ _ -> false; - _ -> true - end, - "xn--" ++ punycode_encode(Name); - false -> - Name - end, - L = length(ASCIIName), - true = (1 =< L) and (L =< 63), - ASCIIName. - - -%%% PUNYCODE (RFC3492) - --define(BASE, 36). --define(TMIN, 1). --define(TMAX, 26). --define(SKEW, 38). --define(DAMP, 700). --define(INITIAL_BIAS, 72). --define(INITIAL_N, 128). - - --spec punycode_encode(nonempty_string()) -> string(). -punycode_encode(Input) -> - N = ?INITIAL_N, - Delta = 0, - Bias = ?INITIAL_BIAS, - Basic = lists:filter(fun(C) -> C =< 16#7f end, Input), - NonBasic = lists:filter(fun(C) -> C > 16#7f end, Input), - L = length(Input), - B = length(Basic), - SNonBasic = lists:usort(NonBasic), - Output1 = if - B > 0 -> Basic ++ "-"; - true -> "" - end, - Output2 = punycode_encode1(Input, SNonBasic, B, B, L, N, Delta, Bias, ""), - Output1 ++ Output2. - - --spec punycode_encode1(Input :: nonempty_string(), SNonBasic :: string(), - B :: non_neg_integer(), H :: any(), L :: non_neg_integer(), N :: number(), - Delta :: number(), Bias :: any(), Out :: any()) -> string(). -punycode_encode1(Input, [M | SNonBasic], B, H, L, N, Delta, Bias, Out) - when H < L -> - Delta1 = Delta + (M - N) * (H + 1), - % let n = m - {NewDelta, NewBias, NewH, NewOut} = - lists:foldl( - fun(C, {ADelta, ABias, AH, AOut}) -> - if - C < M -> - {ADelta + 1, ABias, AH, AOut}; - C == M -> - NewOut = punycode_encode_delta(ADelta, ABias, AOut), - NewBias = adapt(ADelta, H + 1, H == B), - {0, NewBias, AH + 1, NewOut}; - true -> - {ADelta, ABias, AH, AOut} - end - end, {Delta1, Bias, H, Out}, Input), - punycode_encode1( - Input, SNonBasic, B, NewH, L, M + 1, NewDelta + 1, NewBias, NewOut); -punycode_encode1(_Input, _SNonBasic, _B, _H, _L, _N, _Delta, _Bias, Out) -> - lists:reverse(Out). - - --spec punycode_encode_delta(Delta :: number(),_,_) -> nonempty_string(). -punycode_encode_delta(Delta, Bias, Out) -> - punycode_encode_delta(Delta, Bias, Out, ?BASE). - - --spec punycode_encode_delta(number(),_,_,pos_integer()) -> nonempty_string(). -punycode_encode_delta(Delta, Bias, Out, K) -> - T = if - K =< Bias -> ?TMIN; - K >= Bias + ?TMAX -> ?TMAX; - true -> K - Bias - end, - if - Delta < T -> - [codepoint(Delta) | Out]; - true -> - C = T + ((Delta - T) rem (?BASE - T)), - punycode_encode_delta((Delta - T) div (?BASE - T), Bias, - [codepoint(C) | Out], K + ?BASE) - end. - - --spec adapt(integer(),integer(),boolean()) -> integer(). -adapt(Delta, NumPoints, FirstTime) -> - Delta1 = if - FirstTime -> Delta div ?DAMP; - true -> Delta div 2 - end, - Delta2 = Delta1 + (Delta1 div NumPoints), - adapt1(Delta2, 0). - - --spec adapt1(integer(),non_neg_integer()) -> integer(). -adapt1(Delta, K) -> - if - Delta > ((?BASE - ?TMIN) * ?TMAX) div 2 -> - adapt1(Delta div (?BASE - ?TMIN), K + ?BASE); - true -> - K + (((?BASE - ?TMIN + 1) * Delta) div (Delta + ?SKEW)) - end. - - --spec codepoint(char()) -> char(). -codepoint(C) -> - if - (0 =< C) and (C =< 25) -> - C + 97; - (26 =< C) and (C =< 35) -> - C + 22 - end. diff --git a/rebar.config b/rebar.config index a220aa5b1b5..790cf3328ae 100644 --- a/rebar.config +++ b/rebar.config @@ -21,6 +21,7 @@ {mochijson2, ".*", {git, "git://github.com/bjnortier/mochijson2.git", {branch, "master"}}}, {alarms, ".*", {git, "git://github.com/chrzaszcz/alarms.git", {branch, "master"}}}, {fusco, ".*", {git, "git://github.com/esl/fusco.git", {branch, "master"}}}, + {idna, ".*", {git, "git://github.com/benoitc/erlang-idna.git", {tag, "1.0.1"}}}, {seestar, ".*", {git, "git://github.com/iamaleksey/seestar.git", "83e8099b617fffe5af86d4c91d84ce3608accd25"}}, diff --git a/rel/reltool.config.script b/rel/reltool.config.script index b4ba862b839..7514b929895 100644 --- a/rel/reltool.config.script +++ b/rel/reltool.config.script @@ -40,7 +40,8 @@ BaseAppsToInclude = AppsToRun ++ pa, base16, cuesport, - alarms], + alarms, + idna], RemovedApps = [mysql,pgsql,redo,seestar,odbc],