chore(topic_index): add topic validation

This commit is contained in:
Zaiming (Stone) Shi 2023-08-25 10:49:23 +02:00 committed by Andrew Mayorov
parent 33ed53bb6a
commit 558402a68e
No known key found for this signature in database
GPG Key ID: 2837C62ACFBFED5D
2 changed files with 45 additions and 9 deletions

View File

@ -113,7 +113,7 @@
%% @doc Make a search-key for the given topic. %% @doc Make a search-key for the given topic.
-spec make_key(emqx_types:topic(), ID) -> key(ID). -spec make_key(emqx_types:topic(), ID) -> key(ID).
make_key(Topic, ID) when is_binary(Topic) -> make_key(Topic, ID) when is_binary(Topic) ->
Words = words(Topic), Words = filter_words(Topic),
case emqx_topic:wildcard(Words) of case emqx_topic:wildcard(Words) of
true -> true ->
%% it's a wildcard %% it's a wildcard
@ -171,7 +171,7 @@ matches(Topic, NextF, Opts) ->
%% @doc Entrypoint of the search for a given topic. %% @doc Entrypoint of the search for a given topic.
search(Topic, NextF, Opts) -> search(Topic, NextF, Opts) ->
Words = words(Topic), Words = topic_words(Topic),
Base = base_init(Words), Base = base_init(Words),
ORetFirst = proplists:get_bool(return_first, Opts), ORetFirst = proplists:get_bool(return_first, Opts),
OUnique = proplists:get_bool(unique, Opts), OUnique = proplists:get_bool(unique, Opts),
@ -320,18 +320,22 @@ match_add(K, Acc) when is_list(Acc) ->
match_add(K, first) -> match_add(K, first) ->
throw({first, K}). throw({first, K}).
-spec words(emqx_types:topic()) -> [word()]. -spec filter_words(emqx_types:topic()) -> [word()].
words(Topic) when is_binary(Topic) -> filter_words(Topic) when is_binary(Topic) ->
% NOTE % NOTE
% This is almost identical to `emqx_topic:words/1`, but it doesn't convert empty % This is almost identical to `emqx_topic:words/1`, but it doesn't convert empty
% tokens to ''. This is needed to keep ordering of words consistent with what % tokens to ''. This is needed to keep ordering of words consistent with what
% `match_filter/3` expects. % `match_filter/3` expects.
[word(W) || W <- emqx_topic:tokens(Topic)]. [word(W, filter) || W <- emqx_topic:tokens(Topic)].
-spec word(binary()) -> word(). topic_words(Topic) when is_binary(Topic) ->
word(<<"+">>) -> '+'; [word(W, topic) || W <- emqx_topic:tokens(Topic)].
word(<<"#">>) -> '#';
word(Bin) -> Bin. word(<<"+">>, topic) -> error(badarg);
word(<<"#">>, topic) -> error(badarg);
word(<<"+">>, filter) -> '+';
word(<<"#">>, filter) -> '#';
word(Bin, _) -> Bin.
%% match non-wildcard topics %% match non-wildcard topics
match_topics(Topic, {Topic, _} = Key, NextF, Acc) -> match_topics(Topic, {Topic, _} = Key, NextF, Acc) ->

View File

@ -0,0 +1,32 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2023 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_trie_search_tests).
-include_lib("eunit/include/eunit.hrl").
topic_validation_test() ->
NextF = fun(_) -> '$end_of_table' end,
Call = fun(Topic) ->
emqx_trie_search:match(Topic, NextF)
end,
?assertError(badarg, Call(<<"+">>)),
?assertError(badarg, Call(<<"#">>)),
?assertError(badarg, Call(<<"a/+/b">>)),
?assertError(badarg, Call(<<"a/b/#">>)),
?assertEqual(false, Call(<<"a/b/b+">>)),
?assertEqual(false, Call(<<"a/b/c#">>)),
ok.