Files
natsdotnet/src/NATS.Server/Subscriptions/SubjectMatch.cs

117 lines
3.5 KiB
C#

namespace NATS.Server.Subscriptions;
public static class SubjectMatch
{
public const char Pwc = '*'; // partial wildcard
public const char Fwc = '>'; // full wildcard
public const char Sep = '.'; // token separator
public static bool IsValidSubject(string subject)
{
if (string.IsNullOrEmpty(subject))
return false;
bool sawFwc = false;
int start = 0;
for (int i = 0; i <= subject.Length; i++)
{
if (i == subject.Length || subject[i] == Sep)
{
int tokenLen = i - start;
if (tokenLen == 0 || sawFwc)
return false;
if (tokenLen == 1)
{
char c = subject[start];
if (c == Fwc)
sawFwc = true;
else if (c is ' ' or '\t' or '\n' or '\r' or '\f')
return false;
}
else
{
for (int j = start; j < i; j++)
{
char c = subject[j];
if (c is ' ' or '\t' or '\n' or '\r' or '\f')
return false;
}
}
start = i + 1;
}
}
return true;
}
public static bool IsLiteral(string subject)
{
for (int i = 0; i < subject.Length; i++)
{
char c = subject[i];
if (c is Pwc or Fwc)
{
bool atStart = i == 0 || subject[i - 1] == Sep;
bool atEnd = i + 1 == subject.Length || subject[i + 1] == Sep;
if (atStart && atEnd)
return false;
}
}
return true;
}
public static bool IsValidPublishSubject(string subject)
{
return IsValidSubject(subject) && IsLiteral(subject);
}
/// <summary>
/// Match a literal subject against a pattern that may contain wildcards.
/// </summary>
public static bool MatchLiteral(string literal, string pattern)
{
int li = 0, pi = 0;
while (pi < pattern.Length)
{
// Get next pattern token
int pTokenStart = pi;
while (pi < pattern.Length && pattern[pi] != Sep)
pi++;
int pTokenLen = pi - pTokenStart;
if (pi < pattern.Length)
pi++; // skip separator
// Full wildcard -- matches everything remaining
if (pTokenLen == 1 && pattern[pTokenStart] == Fwc)
return li < literal.Length; // must have at least one token left
// Get next literal token
if (li >= literal.Length)
return false;
int lTokenStart = li;
while (li < literal.Length && literal[li] != Sep)
li++;
int lTokenLen = li - lTokenStart;
if (li < literal.Length)
li++; // skip separator
// Partial wildcard -- matches any single token
if (pTokenLen == 1 && pattern[pTokenStart] == Pwc)
continue;
// Literal comparison
if (pTokenLen != lTokenLen)
return false;
if (string.Compare(literal, lTokenStart, pattern, pTokenStart, pTokenLen, StringComparison.Ordinal) != 0)
return false;
}
return li >= literal.Length; // both exhausted
}
}