list.go 3.8 KB

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