MCPcopy
hub / github.com/gofiber/fiber / parseDomainPattern

Function parseDomainPattern

domain.go:55–133  ·  view source on GitHub ↗

parseDomainPattern parses a domain pattern like ":subdomain.example.com" into a domainMatcher. Parameter parts start with ":". Constant labels are lowercased per RFC 4343 (domain names are case-insensitive), but parameter names are preserved as-is so that DomainParam lookups work with the exact name

(pattern string)

Source from the content-addressed store, hash-verified

53// but parameter names are preserved as-is so that DomainParam lookups work with
54// the exact names the caller used (e.g., ":User" → param name "User").
55func parseDomainPattern(pattern string) domainMatcher {
56 pattern = utils.TrimSpace(pattern)
57 // Trim trailing dot of a fully-qualified domain name (RFC 3986),
58 // consistent with Fiber's own host normalization in Subdomains().
59 pattern = utils.TrimRight(pattern, '.')
60
61 // Validate pattern is not empty after trimming
62 if pattern == "" {
63 panic("Domain pattern cannot be empty")
64 }
65
66 // Enforce RFC 1035 total length limit on patterns
67 if len(pattern) > 253 {
68 panic(fmt.Sprintf("Domain pattern '%s' exceeds RFC 1035 maximum of 253 characters (%d chars)",
69 pattern, len(pattern)))
70 }
71
72 parts := strings.Split(pattern, ".")
73
74 // Prevent DoS from patterns with excessive label counts
75 if len(parts) > maxDomainParts {
76 panic(fmt.Sprintf("Domain pattern '%s' has %d parts, which exceeds the maximum of %d",
77 pattern, len(parts), maxDomainParts))
78 }
79
80 m := domainMatcher{
81 parts: make([]string, len(parts)),
82 numParts: len(parts),
83 }
84
85 for i, part := range parts {
86 // Validate no empty labels (e.g., "example..com" is invalid)
87 if part == "" {
88 panic(fmt.Sprintf("Domain pattern '%s' contains empty label at position %d", pattern, i))
89 }
90
91 if part[0] == ':' {
92 // Validate parameter name is not empty
93 if len(part) == 1 {
94 panic(fmt.Sprintf("Domain pattern '%s' contains empty parameter name at position %d", pattern, i))
95 }
96 paramName := part[1:]
97 // Validate parameter name contains only ASCII-safe characters (a-z, A-Z, 0-9, underscore, hyphen).
98 // Using explicit ASCII ranges rather than unicode.IsLetter/IsDigit to reject non-ASCII
99 // characters that are invalid in DNS names.
100 for _, ch := range paramName {
101 if !isASCIIAlphanumeric(ch) && ch != '_' && ch != '-' {
102 panic(fmt.Sprintf("Domain pattern '%s' contains invalid parameter name '%s' with character '%c'", pattern, paramName, ch))
103 }
104 }
105 m.paramIdx = append(m.paramIdx, i)
106 m.paramNames = append(m.paramNames, paramName) // preserve original case
107 m.parts[i] = part // keep ":param" marker for matching
108 } else {
109 // Only lowercase constant labels (RFC 4343)
110 // Enforce RFC 1035 per-label length limit (63 characters)
111 if len(part) > 63 {
112 panic(fmt.Sprintf("Domain pattern '%s' has label '%s' exceeding RFC 1035 limit of 63 characters (%d chars)",

Calls 1

isASCIIAlphanumericFunction · 0.85