class Mongo::URI::SRVProtocol

Parser for a URI using the mongodb+srv protocol, which specifies a DNS to query for SRV records. The driver will query the DNS server for SRV records on {hostname}.{domainname}, prefixed with _mongodb._tcp The SRV records can then be used as the seedlist for a Mongo::Client. The driver also queries for a TXT record providing default connection string options. Only one TXT record is allowed, and only a subset of Mongo::Client options is allowed.

Please refer to the Initial DNS Seedlist Discovery spec for details.

github.com/mongodb/specifications/blob/master/source/initial-dns-seedlist-discovery

@example Use the uri string to make a client connection.

client = Mongo::Client.new('mongodb+srv://test6.test.build.10gen.cc/')

@since 2.5.0

Constants

DOT_PARTITION
FORMAT
INVALID_DOMAIN
INVALID_HOST
INVALID_PORT
INVALID_TXT_RECORD_OPTION
MISMATCHED_DOMAINNAME
MORE_THAN_ONE_TXT_RECORD_FOUND
NO_SRV_RECORDS
RECORD_PREFIX
VALID_TXT_OPTIONS

Public Instance Methods

client_options() click to toggle source

Gets the options hash that needs to be passed to a Mongo::Client on instantiation, so we don't have to merge the txt record options, credentials, and database in at that point - we only have a single point here.

@example Get the client options.

uri.client_options

@return [ Hash ] The options passed to the Mongo::Client

@since 2.5.0

# File lib/mongo/uri/srv_protocol.rb, line 48
def client_options
  opts = @txt_options.merge(ssl: true)
  opts = opts.merge(uri_options).merge(:database => database)
  @user ? opts.merge(credentials) : opts
end

Private Instance Methods

get_records(hostname) click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 114
def get_records(hostname)
  query_name = RECORD_PREFIX + hostname
  records = resolver.getresources(query_name, Resolv::DNS::Resource::IN::SRV).collect do |record|
    record_host = record.target.to_s
    port = record.port
    validate_record!(record_host, hostname)
    "#{record_host}#{HOST_PORT_DELIM}#{port}"
  end
  raise Error::NoSRVRecords.new(NO_SRV_RECORDS % hostname) if records.empty?
  records
end
get_txt_opts(host) click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 134
def get_txt_opts(host)
  records = resolver.getresources(host, Resolv::DNS::Resource::IN::TXT)
  unless records.empty?
    if records.size > 1
      raise Error::InvalidTXTRecord.new(MORE_THAN_ONE_TXT_RECORD_FOUND % host)
    end
    options_string = records[0].strings.join
    parse_txt_options!(options_string)
  end
end
parse_creds_hosts!(string) click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 96
def parse_creds_hosts!(string)
  hostname, creds = split_creds_hosts(string)
  validate_hostname!(hostname)
  records = get_records(hostname)
  @txt_options = get_txt_opts(hostname) || {}
  @servers = parse_servers!(records.join(','))
  @user = parse_user!(creds)
  @password = parse_password!(creds)
end
parse_txt_options!(string) click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 145
def parse_txt_options!(string)
  return {} unless string
  string.split(INDIV_URI_OPTS_DELIM).reduce({}) do |txt_options, opt|
    raise Error::InvalidTXTRecord.new(INVALID_OPTS_VALUE_DELIM) unless opt.index(URI_OPTS_VALUE_DELIM)
    key, value = opt.split(URI_OPTS_VALUE_DELIM)
    raise Error::InvalidTXTRecord.new(INVALID_TXT_RECORD_OPTION) unless VALID_TXT_OPTIONS.include?(key.downcase)
    strategy = URI_OPTION_MAP[key.downcase]
    add_uri_option(strategy, value, txt_options)
    txt_options
  end
end
raise_invalid_error!(details) click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 88
def raise_invalid_error!(details)
  raise Error::InvalidURI.new(@string, details, FORMAT)
end
resolver() click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 92
def resolver
  @resolver ||= Resolv::DNS.new
end
scheme() click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 84
def scheme
  MONGODB_SRV_SCHEME
end
validate_hostname!(hostname) click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 106
def validate_hostname!(hostname)
  raise_invalid_error!(INVALID_HOST) if hostname.empty?
  raise_invalid_error!(INVALID_HOST) if hostname.include?(HOST_DELIM)
  raise_invalid_error!(INVALID_PORT) if hostname.include?(HOST_PORT_DELIM)
  _, _, domain = hostname.partition(DOT_PARTITION)
  raise_invalid_error!(INVALID_DOMAIN) unless domain.include?(DOT_PARTITION)
end
validate_record!(record_host, hostname) click to toggle source
# File lib/mongo/uri/srv_protocol.rb, line 126
def validate_record!(record_host, hostname)
  domainname = hostname.split(DOT_PARTITION)[1..-1]
  host_parts = record_host.split(DOT_PARTITION)
  unless (host_parts.size > domainname.size) && (domainname == host_parts[-domainname.length..-1])
    raise Error::MismatchedDomain.new(MISMATCHED_DOMAINNAME % [record_host, domainname])
  end
end