pub fn pattern_contains(grant: &str, requested: &str) -> boolExpand description
Returns true if every topic matched by requested is also matched by
grant — i.e. grant’s match set ⊇ requested’s match set (grant
contains requested).
This is pattern containment, not topic matching, and the two diverge
once requested is itself a wildcard. An access check must ask containment:
“does my grant cover the whole pattern this client asked to subscribe to?”
topic_matches answers a different question (“does this pattern match
this string?”) and would treat the requested pattern as an opaque topic —
so a one-level grant a.* “matches” the all-levels request a.# (the *
swallows the #) and silently widens the grant. Containment denies that:
a.# reaches deeper than a.* covers.
When requested is a concrete topic (no wildcard) this collapses to exactly
topic_matches(grant, requested), so it is a safe drop-in for an ACL
that must accept both concrete and wildcard subscription requests.
Grammar is the same dot-separated * (single-level) / # (multi-level,
zero-or-more) set as topic_matches. A grant’s # absorbs zero or more
requested segments and the grant continues after it, so an interior #
constrains rather than blanket-allows: a.#.secret contains a.b.secret
but not a.public.
§Conservative by construction
This decides containment with a single left-to-right walk, which is sound
(it never reports containment that does not hold) but not complete. Deciding
the remaining cases means reasoning about every expansion of the request’s
#, and that ∀-branch is exactly the intricate, blowup-prone code an ACL on
client-supplied input should not carry.
The gap is confined to a grant whose * meets a request’s #, where a later
segment would have ruled out the short expansions — e.g. a.*.# does contain
a.#.a (every topic the request admits has ≥2 segments), but this returns
false. Such a pair denies access that could have been allowed; it never
allows access that should have been denied. Grants without a */#
adjacency — every ordinary shape, including a.#, a.*, a.#.b, # — are
decided exactly.