From 24be189728e28ee52be1a2b301597fc7b08d1db2 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Wed, 29 May 2024 12:49:53 +0200 Subject: [PATCH] fix(topic): respect special topic rules when intersecting --- apps/emqx/src/emqx_topic.erl | 9 ++++++++- apps/emqx/test/emqx_topic_SUITE.erl | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/emqx/src/emqx_topic.erl b/apps/emqx/src/emqx_topic.erl index 9cd631508..dd3d4294e 100644 --- a/apps/emqx/src/emqx_topic.erl +++ b/apps/emqx/src/emqx_topic.erl @@ -111,11 +111,18 @@ match(_, _) -> -spec intersection(TopicOrFilter, TopicOrFilter) -> TopicOrFilter | false when TopicOrFilter :: emqx_types:topic(). intersection(Topic1, Topic2) when is_binary(Topic1), is_binary(Topic2) -> - case intersection(words(Topic1), words(Topic2), []) of + case intersect_start(words(Topic1), words(Topic2)) of [] -> false; Intersection -> join(lists:reverse(Intersection)) end. +intersect_start([<<"$", _/bytes>> | _], [W | _]) when ?IS_WILDCARD(W) -> + []; +intersect_start([W | _], [<<"$", _/bytes>> | _]) when ?IS_WILDCARD(W) -> + []; +intersect_start(Words1, Words2) -> + intersection(Words1, Words2, []). + intersection(Words1, ['#'], Acc) -> lists:reverse(Words1, Acc); intersection(['#'], Words2, Acc) -> diff --git a/apps/emqx/test/emqx_topic_SUITE.erl b/apps/emqx/test/emqx_topic_SUITE.erl index 6e0451591..5993fbc40 100644 --- a/apps/emqx/test/emqx_topic_SUITE.erl +++ b/apps/emqx/test/emqx_topic_SUITE.erl @@ -28,6 +28,7 @@ [ wildcard/1, match/2, + intersection/2, validate/1, prepend/2, join/1, @@ -128,6 +129,21 @@ t_match_perf(_) -> true = match(Name, Filter), ok = bench('match/2', fun emqx_topic:match/2, [Name, Filter]). +t_intersect(_) -> + <<"t/global/1/+">> = intersection(<<"t/global/#">>, <<"t/+/1/+">>), + <<"t/global/#">> = intersection(<<"t/global/#">>, <<"#">>), + <<"t/global/#">> = intersection(<<"t/global/#">>, <<"t/global/#">>), + <<"1/2/3/4/5">> = intersection(<<"1/+/3/+/5/#">>, <<"+/2/+/4/+">>), + <<"t/local/1">> = intersection(<<"t/local/1/#">>, <<"t/local/+">>), + false = intersection(<<"t/global/#">>, <<"t/local/+">>), + false = intersection(<<"t/local/1/+">>, <<"t/local/+">>). + +t_sys_intersect(_) -> + <<"$SYS/broker/+">> = intersection(<<"$SYS/broker/#">>, <<"$SYS/+/+">>), + <<"$SYS/broker">> = intersection(<<"$SYS/broker">>, <<"$SYS/+">>), + false = intersection(<<"$SYS/broker">>, <<"+/+">>), + false = intersection(<<"$SYS/broker">>, <<"#">>). + t_validate(_) -> true = validate(<<"a/+/#">>), true = validate(<<"a/b/c/d">>),