PageRenderTime 56ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/mongo/srv/result.rb

https://github.com/mongodb/mongo-ruby-driver
Ruby | 128 lines | 53 code | 16 blank | 59 comment | 4 complexity | e2c4c4ea8be01688eddce04db75db8e8 MD5 | raw file
Possible License(s): Apache-2.0
  1. # frozen_string_literal: true
  2. # encoding: utf-8
  3. # Copyright (C) 2017-2020 MongoDB Inc.
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the 'License');
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an 'AS IS' BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. module Mongo
  17. module Srv
  18. # SRV record lookup result.
  19. #
  20. # Contains server addresses that the query resolved to, and minimum TTL
  21. # of the DNS records.
  22. #
  23. # @api private
  24. class Result
  25. include Address::Validator
  26. # @return [ String ] MISMATCHED_DOMAINNAME Error message format string indicating that an SRV
  27. # record found does not match the domain of a hostname.
  28. MISMATCHED_DOMAINNAME = "Parent domain name in SRV record result (%s) does not match " +
  29. "that of the hostname (%s)".freeze
  30. # @return [ String ] query_hostname The hostname pointing to the DNS records.
  31. attr_reader :query_hostname
  32. # @return [ Array<String> ] address_strs The host strings of the SRV records
  33. # for the query hostname.
  34. attr_reader :address_strs
  35. # @return [ Integer | nil ] min_ttl The smallest TTL found among the
  36. # records (or nil if no records have been added).
  37. attr_accessor :min_ttl
  38. # Create a new object to keep track of the SRV records of the hostname.
  39. #
  40. # @param [ String ] hostname The hostname pointing to the DNS records.
  41. def initialize(hostname)
  42. @query_hostname = hostname
  43. @address_strs = []
  44. @min_ttl = nil
  45. end
  46. # Checks whether there are any records.
  47. #
  48. # @return [ Boolean ] Whether or not there are any records.
  49. def empty?
  50. @address_strs.empty?
  51. end
  52. # Adds a new record.
  53. #
  54. # @param [ Resolv::DNS::Resource ] record An SRV record found for the hostname.
  55. def add_record(record)
  56. record_host = normalize_hostname(record.target.to_s)
  57. port = record.port
  58. validate_hostname!(record_host)
  59. validate_same_origin!(record_host)
  60. address_str = if record_host.index(':')
  61. # IPV6 address
  62. "[#{record_host}]:#{port}"
  63. else
  64. "#{record_host}:#{port}"
  65. end
  66. @address_strs << address_str
  67. if @min_ttl.nil?
  68. @min_ttl = record.ttl
  69. else
  70. @min_ttl = [@min_ttl, record.ttl].min
  71. end
  72. nil
  73. end
  74. private
  75. # Transforms the provided hostname to simplify its validation later on.
  76. #
  77. # This method is safe to call during both initial DNS seed list discovery
  78. # and during SRV monitoring, in that it does not convert invalid hostnames
  79. # into valid ones.
  80. #
  81. # - Converts the hostname to lower case.
  82. # - Removes one trailing dot, if there is exactly one. If the hostname
  83. # has multiple trailing dots, it is unchanged.
  84. #
  85. # @param [ String ] host Hostname to transform.
  86. def normalize_hostname(host)
  87. host = host.downcase
  88. unless host.end_with?('..')
  89. host = host.sub(/\.\z/, '')
  90. end
  91. host
  92. end
  93. # Ensures that a record's domain name matches that of the hostname.
  94. #
  95. # A hostname's domain name consists of each of the '.' delineated
  96. # parts after the first. For example, the hostname 'foo.bar.baz'
  97. # has the domain name 'bar.baz'.
  98. #
  99. # @param [ String ] record_host The host of the SRV record.
  100. #
  101. # @raise [ Mongo::Error::MismatchedDomain ] If the record's domain name doesn't match that of
  102. # the hostname.
  103. def validate_same_origin!(record_host)
  104. domain_name ||= query_hostname.split('.')[1..-1]
  105. host_parts = record_host.split('.')
  106. unless (host_parts.size > domain_name.size) && (domain_name == host_parts[-domain_name.length..-1])
  107. raise Error::MismatchedDomain.new(MISMATCHED_DOMAINNAME % [record_host, domain_name])
  108. end
  109. end
  110. end
  111. end
  112. end