Documentation
¶
Overview ¶
Package dns provides a minimal, high-performance generic matcher for DNS hostnames.
A Router maps dot-separated hostname patterns to caller-provided values, then returns the matched value and any captured parameters. Patterns are matched right-to-left using DNS label boundaries, so shared suffixes such as example.com are stored once.
Hostname matching is ASCII case-insensitive. A single trailing root dot is ignored for both insertion and matching, so example.com and example.com. are equivalent. The package does not parse host:port strings, perform IDNA conversion, or normalize Unicode; callers should provide only the hostname they want to match.
Quick Start ¶
var router dns.Router[string]
router.Insert("example.com", "apex")
router.Insert("{tenant}.example.com", "tenant")
router.Insert("{*subdomain}.example.com", "subdomain")
value, params, ok := router.Match("api.example.com")
_ = value // "tenant"
_ = params.Get("tenant") // "api"
_ = ok // true
Pattern Grammar ¶
Patterns are dot-separated labels made from literal text, named parameters, and left-side catch-all parameters.
Literal labels match themselves case-insensitively. A named parameter is written as {name} and captures one non-empty label. A parameter may have literal text before or after it in the same label, such as api-{region}.example.com or {service}-prod.example.com. Each label may contain at most one parameter.
A catch-all parameter is written as {*name}. It must appear in the leftmost label of the pattern and captures the non-empty leading hostname text before the remaining suffix labels. For example, {*sub}.example.com captures "a.b" from a.b.example.com. A catch-all may have a literal prefix in its leftmost label, such as svc-{*sub}.example.com.
Literal braces are escaped by doubling them: {{ matches a literal { and }} matches a literal }. Escaped braces may also appear inside parameter names.
Matching Behavior ¶
When more than one pattern could match, dns chooses deterministically while walking labels from right to left: literal labels beat parameter labels, parameter labels with more literal text are tried first, and catch-all patterns are considered last.
Match looks up an exact hostname. MatchInto is the same operation using a caller-provided *Params value as reusable storage. MatchSuffix and MatchSuffixInto return the best whole-label hostname suffix plus the unmatched leading prefix, which is useful for zone-style dispatch. Clone returns an independent copy of a Router's matching state.
Index ¶
- Variables
- type ConflictError
- type Param
- type Params
- type Router
- func (r *Router[T]) Clone() Router[T]
- func (r *Router[T]) Insert(pattern string, value T)
- func (r *Router[T]) Match(hostname string) (T, Params, bool)
- func (r *Router[T]) MatchInto(hostname string, params *Params) (T, bool)
- func (r *Router[T]) MatchSuffix(hostname string) (SuffixMatch[T], bool)
- func (r *Router[T]) MatchSuffixInto(hostname string, params *Params) (SuffixMatch[T], bool)
- func (r *Router[T]) TryInsert(pattern string, value T) error
- type SuffixMatch
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidHostname reports malformed dot-separated hostname structure. ErrInvalidHostname = errors.New("hostnames must contain non-empty labels") // ErrInvalidParamLabel reports a pattern label that contains more than one // parameter. ErrInvalidParamLabel = errors.New("only one parameter is allowed per hostname label") // ErrInvalidParam reports malformed parameter syntax or an invalid // parameter name. ErrInvalidParam = match.ErrInvalidParam // ErrInvalidCatchAll reports a catch-all parameter outside the leftmost // pattern label. ErrInvalidCatchAll = errors.New("catch-all parameters are only allowed at the start of a hostname pattern") )
Functions ¶
This section is empty.
Types ¶
type ConflictError ¶
type ConflictError struct {
// Pattern is the pattern that failed to insert.
Pattern string
// With is the previously registered pattern that conflicts with Pattern.
With string
}
ConflictError reports a pattern that cannot be inserted because it overlaps an already registered pattern.
func (*ConflictError) Error ¶
func (e *ConflictError) Error() string
Error returns a human-readable description of the pattern conflict.
type Params ¶
Params stores captured hostname parameters in pattern order.
type Router ¶
type Router[T any] struct { // contains filtered or unexported fields }
Router maps DNS hostname patterns to caller-provided values.
The zero value is ready to use. After patterns are registered, a Router may be used by multiple goroutines for matching. Callers that insert patterns while other goroutines use the router must synchronize access.
func (*Router[T]) Clone ¶
Clone returns a Router containing a deep copy of r's matching state.
Future inserts into the returned Router do not mutate r. Stored values are copied by assignment.
func (*Router[T]) Insert ¶
Insert registers pattern with value.
It panics with the same errors returned by TryInsert when pattern is invalid or conflicts with an existing pattern.
func (*Router[T]) Match ¶
Match returns the value and parameters for hostname.
Hostname matching is ASCII case-insensitive. A single trailing root dot is ignored, so example.com and example.com. are equivalent. The boolean result is false when no registered pattern matches or hostname is malformed.
func (*Router[T]) MatchInto ¶
MatchInto returns the value for hostname using params as parameter storage.
Params is reset before matching and must be non-nil. Use NewParams to create a reusable Params buffer large enough for the expected number of captures.
func (*Router[T]) MatchSuffix ¶
func (r *Router[T]) MatchSuffix(hostname string) (SuffixMatch[T], bool)
MatchSuffix returns the value, parameters, and unmatched prefix for the best registered pattern that matches the right-hand suffix of hostname.
The boolean result is false when no registered pattern matches a whole-label suffix of hostname. When multiple patterns match, the pattern that consumes the most hostname labels wins.
func (*Router[T]) MatchSuffixInto ¶
func (r *Router[T]) MatchSuffixInto(hostname string, params *Params) (SuffixMatch[T], bool)
MatchSuffixInto is like MatchSuffix, but uses params as parameter storage.
Params is reset before matching and must be non-nil. Use NewParams to create a reusable Params buffer large enough for the expected number of captures.
type SuffixMatch ¶
SuffixMatch contains the result of a successful suffix match.
Prefix is the unmatched labels to the left of the matched suffix. It is empty when the match consumes the full hostname.