1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 //go:generate go run gen.go
7 // Package publicsuffix provides a public suffix list based on data from
8 // http://publicsuffix.org/. A public suffix is one under which Internet users
9 // can directly register names.
10 package publicsuffix // import "golang.org/x/net/publicsuffix"
12 // TODO: specify case sensitivity and leading/trailing dot behavior for
13 // func PublicSuffix and func EffectiveTLDPlusOne.
21 // List implements the cookiejar.PublicSuffixList interface by calling the
22 // PublicSuffix function.
23 var List cookiejar.PublicSuffixList = list{}
27 func (list) PublicSuffix(domain string) string {
28 ps, _ := PublicSuffix(domain)
32 func (list) String() string {
36 // PublicSuffix returns the public suffix of the domain using a copy of the
37 // publicsuffix.org database compiled into the library.
39 // icann is whether the public suffix is managed by the Internet Corporation
40 // for Assigned Names and Numbers. If not, the public suffix is privately
41 // managed. For example, foo.org and foo.co.uk are ICANN domains,
42 // foo.dyndns.org and foo.blogspot.co.uk are private domains.
44 // Use cases for distinguishing ICANN domains like foo.com from private
45 // domains like foo.appspot.com can be found at
46 // https://wiki.mozilla.org/Public_Suffix_List/Use_Cases
47 func PublicSuffix(domain string) (publicSuffix string, icann bool) {
48 lo, hi := uint32(0), uint32(numTLD)
49 s, suffix, wildcard := domain, len(domain), false
52 dot := strings.LastIndex(s, ".")
59 f := find(s[1+dot:], lo, hi)
64 u := nodes[f] >> (nodesBitsTextOffset + nodesBitsTextLength)
65 icann = u&(1<<nodesBitsICANN-1) != 0
67 u = children[u&(1<<nodesBitsChildren-1)]
68 lo = u & (1<<childrenBitsLo - 1)
70 hi = u & (1<<childrenBitsHi - 1)
72 switch u & (1<<childrenBitsNodeType - 1) {
75 case nodeTypeException:
79 u >>= childrenBitsNodeType
80 wildcard = u&(1<<childrenBitsWildcard-1) != 0
87 if suffix == len(domain) {
88 // If no rules match, the prevailing rule is "*".
89 return domain[1+strings.LastIndex(domain, "."):], icann
91 return domain[suffix:], icann
94 const notFound uint32 = 1<<32 - 1
96 // find returns the index of the node in the range [lo, hi) whose label equals
97 // label, or notFound if there is no such node. The range is assumed to be in
98 // strictly increasing node label order.
99 func find(label string, lo, hi uint32) uint32 {
101 mid := lo + (hi-lo)/2
105 } else if s == label {
114 // nodeLabel returns the label for the i'th node.
115 func nodeLabel(i uint32) string {
117 length := x & (1<<nodesBitsTextLength - 1)
118 x >>= nodesBitsTextLength
119 offset := x & (1<<nodesBitsTextOffset - 1)
120 return text[offset : offset+length]
123 // EffectiveTLDPlusOne returns the effective top level domain plus one more
124 // label. For example, the eTLD+1 for "foo.bar.golang.org" is "golang.org".
125 func EffectiveTLDPlusOne(domain string) (string, error) {
126 suffix, _ := PublicSuffix(domain)
127 if len(domain) <= len(suffix) {
128 return "", fmt.Errorf("publicsuffix: cannot derive eTLD+1 for domain %q", domain)
130 i := len(domain) - len(suffix) - 1
131 if domain[i] != '.' {
132 return "", fmt.Errorf("publicsuffix: invalid public suffix %q for domain %q", suffix, domain)
134 return domain[1+strings.LastIndex(domain[:i], "."):], nil