Fixes and clean the new topic matcher from israellot

This commit is contained in:
Sébastien Warin
2018-05-15 17:39:45 +02:00
parent 5287bf5cac
commit ba66c108fa
4 changed files with 195 additions and 29 deletions
@@ -4,46 +4,116 @@ namespace MQTTnet.Server
{
public static class MqttTopicFilterComparer
{
private static readonly char[] TopicLevelSeparator = { '/' };
private const char LEVEL_SEPARATOR = '/';
private const char WILDCARD_MULTI_LEVEL = '#';
private const char WILDCARD_SINGLE_LEVEL = '+';
public static bool IsMatch(string topic, string filter)
{
if (topic == null) throw new ArgumentNullException(nameof(topic));
if (filter == null) throw new ArgumentNullException(nameof(filter));
if (string.IsNullOrEmpty(topic)) throw new ArgumentNullException(nameof(topic));
if (string.IsNullOrEmpty(filter)) throw new ArgumentNullException(nameof(filter));
if (string.Equals(topic, filter, StringComparison.Ordinal))
int spos = 0;
int slen = filter.Length;
int tpos = 0;
int tlen = topic.Length;
while (spos < slen && tpos < tlen)
{
return true;
}
var fragmentsTopic = topic.Split(TopicLevelSeparator, StringSplitOptions.None);
var fragmentsFilter = filter.Split(TopicLevelSeparator, StringSplitOptions.None);
// # > In either case it MUST be the last character specified in the Topic Filter [MQTT-4.7.1-2].
for (var i = 0; i < fragmentsFilter.Length; i++)
{
if (fragmentsFilter[i] == "+")
if (filter[spos] == topic[tpos])
{
continue;
if (tpos == tlen - 1)
{
/* Check for e.g. foo matching foo/# */
if (spos == slen - 3
&& filter[spos + 1] == LEVEL_SEPARATOR
&& filter[spos + 2] == WILDCARD_MULTI_LEVEL)
{
return true;
}
}
spos++;
tpos++;
if (spos == slen && tpos == tlen)
{
return true;
}
else if (tpos == tlen && spos == slen - 1 && filter[spos] == WILDCARD_SINGLE_LEVEL)
{
if (spos > 0 && filter[spos - 1] != LEVEL_SEPARATOR)
{
// Invalid filter string
return false;
}
spos++;
return true;
}
}
if (fragmentsFilter[i] == "#")
else
{
return true;
}
if (i >= fragmentsTopic.Length)
{
return false;
}
if (!string.Equals(fragmentsFilter[i], fragmentsTopic[i], StringComparison.Ordinal))
{
return false;
if (filter[spos] == WILDCARD_SINGLE_LEVEL)
{
/* Check for bad "+foo" or "a/+foo" subscription */
if (spos > 0 && filter[spos - 1] != LEVEL_SEPARATOR)
{
// Invalid filter string
return false;
}
/* Check for bad "foo+" or "foo+/a" subscription */
if (spos < slen - 1 && filter[spos + 1] != LEVEL_SEPARATOR)
{
// Invalid filter string
return false;
}
spos++;
while (tpos < tlen && topic[tpos] != LEVEL_SEPARATOR)
{
tpos++;
}
if (tpos == tlen && spos == slen)
{
return true;
}
}
else if (filter[spos] == WILDCARD_MULTI_LEVEL)
{
if (spos > 0 && filter[spos - 1] != LEVEL_SEPARATOR)
{
// Invalid filter string
return false;
}
if (spos + 1 != slen)
{
// Invalid filter string
return false;
}
else
{
return true;
}
}
else
{
/* Check for e.g. foo/bar matching foo/+/# */
if (spos > 0
&& spos + 2 == slen
&& tpos == tlen
&& filter[spos - 1] == WILDCARD_SINGLE_LEVEL
&& filter[spos] == LEVEL_SEPARATOR
&& filter[spos + 1] == WILDCARD_MULTI_LEVEL)
{
return true;
}
return false;
}
}
}
if (tpos < tlen || spos < slen)
{
return false;
}
return fragmentsTopic.Length == fragmentsFilter.Length;
return false;
}
}
}