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  }