OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / publicsuffix / list.go
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.
4
5 //go:generate go run gen.go
6
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"
11
12 // TODO: specify case sensitivity and leading/trailing dot behavior for
13 // func PublicSuffix and func EffectiveTLDPlusOne.
14
15 import (
16         "fmt"
17         "net/http/cookiejar"
18         "strings"
19 )
20
21 // List implements the cookiejar.PublicSuffixList interface by calling the
22 // PublicSuffix function.
23 var List cookiejar.PublicSuffixList = list{}
24
25 type list struct{}
26
27 func (list) PublicSuffix(domain string) string {
28         ps, _ := PublicSuffix(domain)
29         return ps
30 }
31
32 func (list) String() string {
33         return version
34 }
35
36 // PublicSuffix returns the public suffix of the domain using a copy of the
37 // publicsuffix.org database compiled into the library.
38 //
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.
43 //
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
50 loop:
51         for {
52                 dot := strings.LastIndex(s, ".")
53                 if wildcard {
54                         suffix = 1 + dot
55                 }
56                 if lo == hi {
57                         break
58                 }
59                 f := find(s[1+dot:], lo, hi)
60                 if f == notFound {
61                         break
62                 }
63
64                 u := nodes[f] >> (nodesBitsTextOffset + nodesBitsTextLength)
65                 icann = u&(1<<nodesBitsICANN-1) != 0
66                 u >>= nodesBitsICANN
67                 u = children[u&(1<<nodesBitsChildren-1)]
68                 lo = u & (1<<childrenBitsLo - 1)
69                 u >>= childrenBitsLo
70                 hi = u & (1<<childrenBitsHi - 1)
71                 u >>= childrenBitsHi
72                 switch u & (1<<childrenBitsNodeType - 1) {
73                 case nodeTypeNormal:
74                         suffix = 1 + dot
75                 case nodeTypeException:
76                         suffix = 1 + len(s)
77                         break loop
78                 }
79                 u >>= childrenBitsNodeType
80                 wildcard = u&(1<<childrenBitsWildcard-1) != 0
81
82                 if dot == -1 {
83                         break
84                 }
85                 s = s[:dot]
86         }
87         if suffix == len(domain) {
88                 // If no rules match, the prevailing rule is "*".
89                 return domain[1+strings.LastIndex(domain, "."):], icann
90         }
91         return domain[suffix:], icann
92 }
93
94 const notFound uint32 = 1<<32 - 1
95
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 {
100         for lo < hi {
101                 mid := lo + (hi-lo)/2
102                 s := nodeLabel(mid)
103                 if s < label {
104                         lo = mid + 1
105                 } else if s == label {
106                         return mid
107                 } else {
108                         hi = mid
109                 }
110         }
111         return notFound
112 }
113
114 // nodeLabel returns the label for the i'th node.
115 func nodeLabel(i uint32) string {
116         x := nodes[i]
117         length := x & (1<<nodesBitsTextLength - 1)
118         x >>= nodesBitsTextLength
119         offset := x & (1<<nodesBitsTextOffset - 1)
120         return text[offset : offset+length]
121 }
122
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)
129         }
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)
133         }
134         return domain[1+strings.LastIndex(domain[:i], "."):], nil
135 }