You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

136 lines
3.8 KiB

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