gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/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  //go:generate go run gen.go
     6  
     7  // Package publicsuffix provides a public suffix list based on data from
     8  // https://publicsuffix.org/
     9  //
    10  // A public suffix is one under which Internet users can directly register
    11  // names. It is related to, but different from, a TLD (top level domain).
    12  //
    13  // "com" is a TLD (top level domain). Top level means it has no dots.
    14  //
    15  // "com" is also a public suffix. Amazon and Google have registered different
    16  // siblings under that domain: "amazon.com" and "google.com".
    17  //
    18  // "au" is another TLD, again because it has no dots. But it's not "amazon.au".
    19  // Instead, it's "amazon.com.au".
    20  //
    21  // "com.au" isn't an actual TLD, because it's not at the top level (it has
    22  // dots). But it is an eTLD (effective TLD), because that's the branching point
    23  // for domain name registrars.
    24  //
    25  // Another name for "an eTLD" is "a public suffix". Often, what's more of
    26  // interest is the eTLD+1, or one more label than the public suffix. For
    27  // example, browsers partition read/write access to HTTP cookies according to
    28  // the eTLD+1. Web pages served from "amazon.com.au" can't read cookies from
    29  // "google.com.au", but web pages served from "maps.google.com" can share
    30  // cookies from "www.google.com", so you don't have to sign into Google Maps
    31  // separately from signing into Google Web Search. Note that all four of those
    32  // domains have 3 labels and 2 dots. The first two domains are each an eTLD+1,
    33  // the last two are not (but share the same eTLD+1: "google.com").
    34  //
    35  // All of these domains have the same eTLD+1:
    36  //   - "www.books.amazon.co.uk"
    37  //   - "books.amazon.co.uk"
    38  //   - "amazon.co.uk"
    39  //
    40  // Specifically, the eTLD+1 is "amazon.co.uk", because the eTLD is "co.uk".
    41  //
    42  // There is no closed form algorithm to calculate the eTLD of a domain.
    43  // Instead, the calculation is data driven. This package provides a
    44  // pre-compiled snapshot of Mozilla's PSL (Public Suffix List) data at
    45  // https://publicsuffix.org/
    46  package publicsuffix // import "gitee.com/ks-custle/core-gm/net/publicsuffix"
    47  
    48  // TODO: specify case sensitivity and leading/trailing dot behavior for
    49  // func PublicSuffix and func EffectiveTLDPlusOne.
    50  
    51  import (
    52  	"fmt"
    53  	"strings"
    54  
    55  	"gitee.com/ks-custle/core-gm/gmhttp/cookiejar"
    56  )
    57  
    58  // List implements the cookiejar.PublicSuffixList interface by calling the
    59  // PublicSuffix function.
    60  var List cookiejar.PublicSuffixList = list{}
    61  
    62  type list struct{}
    63  
    64  func (list) PublicSuffix(domain string) string {
    65  	ps, _ := PublicSuffix(domain)
    66  	return ps
    67  }
    68  
    69  func (list) String() string {
    70  	return version
    71  }
    72  
    73  // PublicSuffix returns the public suffix of the domain using a copy of the
    74  // publicsuffix.org database compiled into the library.
    75  //
    76  // icann is whether the public suffix is managed by the Internet Corporation
    77  // for Assigned Names and Numbers. If not, the public suffix is either a
    78  // privately managed domain (and in practice, not a top level domain) or an
    79  // unmanaged top level domain (and not explicitly mentioned in the
    80  // publicsuffix.org list). For example, "foo.org" and "foo.co.uk" are ICANN
    81  // domains, "foo.dyndns.org" and "foo.blogspot.co.uk" are private domains and
    82  // "cromulent" is an unmanaged top level domain.
    83  //
    84  // Use cases for distinguishing ICANN domains like "foo.com" from private
    85  // domains like "foo.appspot.com" can be found at
    86  // https://wiki.mozilla.org/Public_Suffix_List/Use_Cases
    87  func PublicSuffix(domain string) (publicSuffix string, icann bool) {
    88  	lo, hi := uint32(0), uint32(numTLD)
    89  	s, suffix, icannNode, wildcard := domain, len(domain), false, false
    90  loop:
    91  	for {
    92  		dot := strings.LastIndex(s, ".")
    93  		if wildcard {
    94  			icann = icannNode
    95  			suffix = 1 + dot
    96  		}
    97  		if lo == hi {
    98  			break
    99  		}
   100  		f := find(s[1+dot:], lo, hi)
   101  		if f == notFound {
   102  			break
   103  		}
   104  
   105  		u := nodes[f] >> (nodesBitsTextOffset + nodesBitsTextLength)
   106  		icannNode = u&(1<<nodesBitsICANN-1) != 0
   107  		u >>= nodesBitsICANN
   108  		u = children[u&(1<<nodesBitsChildren-1)]
   109  		lo = u & (1<<childrenBitsLo - 1)
   110  		u >>= childrenBitsLo
   111  		hi = u & (1<<childrenBitsHi - 1)
   112  		u >>= childrenBitsHi
   113  		switch u & (1<<childrenBitsNodeType - 1) {
   114  		case nodeTypeNormal:
   115  			suffix = 1 + dot
   116  		case nodeTypeException:
   117  			suffix = 1 + len(s)
   118  			break loop
   119  		}
   120  		u >>= childrenBitsNodeType
   121  		wildcard = u&(1<<childrenBitsWildcard-1) != 0
   122  		if !wildcard {
   123  			icann = icannNode
   124  		}
   125  
   126  		if dot == -1 {
   127  			break
   128  		}
   129  		s = s[:dot]
   130  	}
   131  	if suffix == len(domain) {
   132  		// If no rules match, the prevailing rule is "*".
   133  		return domain[1+strings.LastIndex(domain, "."):], icann
   134  	}
   135  	return domain[suffix:], icann
   136  }
   137  
   138  const notFound uint32 = 1<<32 - 1
   139  
   140  // find returns the index of the node in the range [lo, hi) whose label equals
   141  // label, or notFound if there is no such node. The range is assumed to be in
   142  // strictly increasing node label order.
   143  func find(label string, lo, hi uint32) uint32 {
   144  	for lo < hi {
   145  		mid := lo + (hi-lo)/2
   146  		s := nodeLabel(mid)
   147  		if s < label {
   148  			lo = mid + 1
   149  		} else if s == label {
   150  			return mid
   151  		} else {
   152  			hi = mid
   153  		}
   154  	}
   155  	return notFound
   156  }
   157  
   158  // nodeLabel returns the label for the i'th node.
   159  func nodeLabel(i uint32) string {
   160  	x := nodes[i]
   161  	length := x & (1<<nodesBitsTextLength - 1)
   162  	x >>= nodesBitsTextLength
   163  	offset := x & (1<<nodesBitsTextOffset - 1)
   164  	return text[offset : offset+length]
   165  }
   166  
   167  // EffectiveTLDPlusOne returns the effective top level domain plus one more
   168  // label. For example, the eTLD+1 for "foo.bar.golang.org" is "golang.org".
   169  func EffectiveTLDPlusOne(domain string) (string, error) {
   170  	if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") || strings.Contains(domain, "..") {
   171  		return "", fmt.Errorf("publicsuffix: empty label in domain %q", domain)
   172  	}
   173  
   174  	suffix, _ := PublicSuffix(domain)
   175  	if len(domain) <= len(suffix) {
   176  		return "", fmt.Errorf("publicsuffix: cannot derive eTLD+1 for domain %q", domain)
   177  	}
   178  	i := len(domain) - len(suffix) - 1
   179  	if domain[i] != '.' {
   180  		return "", fmt.Errorf("publicsuffix: invalid public suffix %q for domain %q", suffix, domain)
   181  	}
   182  	return domain[1+strings.LastIndex(domain[:i], "."):], nil
   183  }