DomainAliasStorage::buildPatterns() enumerates wildcard match candidates for loadByHostname(). The hand-rolled loop misses some masks:
- 4-segment hostnames: 13 of 14 useful patterns generated. Mask 9 (
*.two.example.*— wildcards on both ends, literals in the middle) is unreachable. - 5-segment hostnames: 19 of 30 useful patterns generated. 11 masks unreachable.
Replace the loop with a deterministic bitmask enumeration that produces exactly 2^N − 2 patterns for an N-segment hostname (every wildcard mask except all-literal — the exact hostname, handled separately by getPatterns() — and all-wildcard, which would match anything and is not a useful candidate).
Practical impact in 3.x
Bounded. The validator's single-host-wildcard cap (still in place at 3.x — see #3588169) means stored multi-host-wildcard aliases cannot exist via the normal save path. The previously-unreachable patterns this MR enumerates can only have a stored alias if config was imported via direct YAML edit or migrated from D6/D7. So the user-visible "aliases now match" effect is small for typical 3.x sites.
The full benefit lands once a future issue raises the host-wildcard cap (out of scope here, depends on DomainAliasPatternResolver::replaceWildcards() hardening). This MR is the prerequisite refactor: no point in raising the cap if the candidate enumeration is incomplete.
The change is still a strict improvement in 3.x:
- Cleaner code (5-branch hand-roll → 1 bitmask loop), generalises to any segment count.
array_unique()call ingetPatterns()is now provably unnecessary and dropped (the bitmask emits no duplicates).- Test fixtures lock in the new coverage so the next host-cap-raise MR doesn't have to re-derive what
buildPatterns()should emit.
Proposed fix
Replace the hand-rolled five-branch loop with a deterministic bitmask enumeration:
private function buildPatterns(array $parts): array { $count = count($parts); $patterns = []; // Iterate over every wildcard mask except all-literal // (mask 0, the exact hostname, handled separately by // getPatterns()) and all-wildcard (which would match // everything and is therefore not a useful candidate). for ($mask = 1; $mask < (1 << $count) - 1; $mask++) { $temp = $parts; for ($j = 0; $j < $count; $j++) { if ($mask & (1 << $j)) { $temp[$j] = '*'; } } $patterns[] = implode('.', $temp); } return $patterns; }
Test plan
- Extend
DomainAliasSortTest:one.two.example.com:80fixture: all 14 wildcard masks (mask 9 added; the duplicate entry removed; mask 11 added).- New
a.b.c.d.e:80fixture: 91 patterns covering every mask for a 5-segment hostname.
Out of scope (separate issues)
- Raising the host-wildcard limit to match the README's "max 3" claim.
DomainAliasPatternResolversubstitution hardening (prerequisite for raising the cap).
Audit context
Surfaced while auditing #3588155 (sort comparator and port-pattern priority). The omission is logically separate from the sort/priority work; landed here as its own issue.
Issue fork domain-3588168
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mably commentedComment #3
mably commentedComment #5
mably commentedComment #6
mably commentedComment #8
mably commented