Subdomains returns a slice of subdomains from the host, excluding the last `offset` components. If the offset is negative or exceeds the number of subdomains, an empty slice is returned. If the offset is zero every label (no trimming) is returned.
(offset ...int)
| 1127 | // If the offset is negative or exceeds the number of subdomains, an empty slice is returned. |
| 1128 | // If the offset is zero every label (no trimming) is returned. |
| 1129 | func (r *DefaultReq) Subdomains(offset ...int) []string { |
| 1130 | o := 2 |
| 1131 | if len(offset) > 0 { |
| 1132 | o = offset[0] |
| 1133 | } |
| 1134 | |
| 1135 | // Negative offset, return nothing. |
| 1136 | if o < 0 { |
| 1137 | return []string{} |
| 1138 | } |
| 1139 | |
| 1140 | // Normalize host according to RFC 3986 |
| 1141 | host := r.Hostname() |
| 1142 | // Trim the trailing dot of a fully-qualified domain |
| 1143 | if strings.HasSuffix(host, ".") { |
| 1144 | host = utils.TrimRight(host, '.') |
| 1145 | } |
| 1146 | host = utilsstrings.ToLower(host) |
| 1147 | |
| 1148 | // Decode punycode labels only when necessary |
| 1149 | if strings.Contains(host, "xn--") { |
| 1150 | if u, err := idna.Lookup.ToUnicode(host); err == nil { |
| 1151 | host = utilsstrings.ToLower(u) |
| 1152 | } |
| 1153 | } |
| 1154 | |
| 1155 | // Return nothing for IP addresses |
| 1156 | ip := host |
| 1157 | if strings.HasPrefix(ip, "[") && strings.HasSuffix(ip, "]") { |
| 1158 | ip = ip[1 : len(ip)-1] |
| 1159 | } |
| 1160 | if utils.IsIPv4(ip) || utils.IsIPv6(ip) { |
| 1161 | return []string{} |
| 1162 | } |
| 1163 | |
| 1164 | // Use stack-allocated array for typical domain names (up to 8 labels) |
| 1165 | // This avoids heap allocation for most common cases |
| 1166 | var partsBuf [8]string |
| 1167 | parts := partsBuf[:0] |
| 1168 | |
| 1169 | for part := range strings.SplitSeq(host, ".") { |
| 1170 | parts = append(parts, part) |
| 1171 | } |
| 1172 | |
| 1173 | // offset == 0, caller wants everything. |
| 1174 | if o == 0 { |
| 1175 | // Need to return a copy since partsBuf is on the stack |
| 1176 | result := make([]string, len(parts)) |
| 1177 | copy(result, parts) |
| 1178 | return result |
| 1179 | } |
| 1180 | |
| 1181 | // If we trim away the whole slice (or more), nothing remains. |
| 1182 | if o >= len(parts) { |
| 1183 | return []string{} |
| 1184 | } |
| 1185 | |
| 1186 | // Return a heap-allocated copy of the relevant portion |