github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/publicsuffix/list.go (about) 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 // Package publicsuffix provides a public suffix list based on data from 6 // http://publicsuffix.org/. A public suffix is one under which Internet users 7 // can directly register names. 8 package publicsuffix // import "golang.org/x/net/publicsuffix" 9 10 // TODO: specify case sensitivity and leading/trailing dot behavior for 11 // func PublicSuffix and func EffectiveTLDPlusOne. 12 13 import ( 14 "fmt" 15 "net/http/cookiejar" 16 "strings" 17 ) 18 19 // List implements the cookiejar.PublicSuffixList interface by calling the 20 // PublicSuffix function. 21 var List cookiejar.PublicSuffixList = list{} 22 23 type list struct{} 24 25 func (list) PublicSuffix(domain string) string { 26 ps, _ := PublicSuffix(domain) 27 return ps 28 } 29 30 func (list) String() string { 31 return version 32 } 33 34 // PublicSuffix returns the public suffix of the domain using a copy of the 35 // publicsuffix.org database compiled into the library. 36 // 37 // icann is whether the public suffix is managed by the Internet Corporation 38 // for Assigned Names and Numbers. If not, the public suffix is privately 39 // managed. For example, foo.org and foo.co.uk are ICANN domains, 40 // foo.dyndns.org and foo.blogspot.co.uk are private domains. 41 // 42 // Use cases for distinguishing ICANN domains like foo.com from private 43 // domains like foo.appspot.com can be found at 44 // https://wiki.mozilla.org/Public_Suffix_List/Use_Cases 45 func PublicSuffix(domain string) (publicSuffix string, icann bool) { 46 lo, hi := uint32(0), uint32(numTLD) 47 s, suffix, wildcard := domain, len(domain), false 48 loop: 49 for { 50 dot := strings.LastIndex(s, ".") 51 if wildcard { 52 suffix = 1 + dot 53 } 54 if lo == hi { 55 break 56 } 57 f := find(s[1+dot:], lo, hi) 58 if f == notFound { 59 break 60 } 61 62 u := nodes[f] >> (nodesBitsTextOffset + nodesBitsTextLength) 63 icann = u&(1<<nodesBitsICANN-1) != 0 64 u >>= nodesBitsICANN 65 u = children[u&(1<<nodesBitsChildren-1)] 66 lo = u & (1<<childrenBitsLo - 1) 67 u >>= childrenBitsLo 68 hi = u & (1<<childrenBitsHi - 1) 69 u >>= childrenBitsHi 70 switch u & (1<<childrenBitsNodeType - 1) { 71 case nodeTypeNormal: 72 suffix = 1 + dot 73 case nodeTypeException: 74 suffix = 1 + len(s) 75 break loop 76 } 77 u >>= childrenBitsNodeType 78 wildcard = u&(1<<childrenBitsWildcard-1) != 0 79 80 if dot == -1 { 81 break 82 } 83 s = s[:dot] 84 } 85 if suffix == len(domain) { 86 // If no rules match, the prevailing rule is "*". 87 return domain[1+strings.LastIndex(domain, "."):], icann 88 } 89 return domain[suffix:], icann 90 } 91 92 const notFound uint32 = 1<<32 - 1 93 94 // find returns the index of the node in the range [lo, hi) whose label equals 95 // label, or notFound if there is no such node. The range is assumed to be in 96 // strictly increasing node label order. 97 func find(label string, lo, hi uint32) uint32 { 98 for lo < hi { 99 mid := lo + (hi-lo)/2 100 s := nodeLabel(mid) 101 if s < label { 102 lo = mid + 1 103 } else if s == label { 104 return mid 105 } else { 106 hi = mid 107 } 108 } 109 return notFound 110 } 111 112 // nodeLabel returns the label for the i'th node. 113 func nodeLabel(i uint32) string { 114 x := nodes[i] 115 length := x & (1<<nodesBitsTextLength - 1) 116 x >>= nodesBitsTextLength 117 offset := x & (1<<nodesBitsTextOffset - 1) 118 return text[offset : offset+length] 119 } 120 121 // EffectiveTLDPlusOne returns the effective top level domain plus one more 122 // label. For example, the eTLD+1 for "foo.bar.golang.org" is "golang.org". 123 func EffectiveTLDPlusOne(domain string) (string, error) { 124 suffix, _ := PublicSuffix(domain) 125 if len(domain) <= len(suffix) { 126 return "", fmt.Errorf("publicsuffix: cannot derive eTLD+1 for domain %q", domain) 127 } 128 i := len(domain) - len(suffix) - 1 129 if domain[i] != '.' { 130 return "", fmt.Errorf("publicsuffix: invalid public suffix %q for domain %q", suffix, domain) 131 } 132 return domain[1+strings.LastIndex(domain[:i], "."):], nil 133 }