class Mongo::URIParser

Constants

AUTH_REGEX
HOST_REGEX
MONGODB_URI_MATCHER
MONGODB_URI_SPEC
NODE_REGEX
OPT_ATTRS
OPT_CASE_SENSITIVE
OPT_CONV
OPT_ERR
OPT_VALID
PATH_REGEX
PORT_REGEX
READ_PREFERENCES
SPEC_ATTRS

Attributes

authmechanism[R]
auths[R]
authsource[R]
canonicalizehostname[R]
connect[R]
connecttimeoutms[R]
db_name[R]
fsync[R]
gssapiservicename[R]
journal[R]
nodes[R]
pool_size[R]
readpreference[R]
replicaset[R]
safe[R]
slaveok[R]
sockettimeoutms[R]
ssl[R]
w[R]
wtimeout[R]
wtimeoutms[R]

Public Class Methods

new(uri) click to toggle source

Parse a MongoDB URI. This method is used by Mongo::MongoClient.from_uri. Returns an array of nodes and an array of db authorizations, if applicable.

@note Passwords can contain any character except for ','

@param [String] uri The MongoDB URI string.

# File lib/mongo/functional/uri_parser.rb, line 162
def initialize(uri)
  if uri.start_with?('mongodb://')
    uri = uri[10..-1]
  else
    raise MongoArgumentError, "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
  end

  hosts, opts = uri.split('?')
  parse_options(opts)
  parse_hosts(hosts)
  validate_connect
end

Public Instance Methods

connect?() click to toggle source

Whether to immediately connect to the MongoDB node. Defaults to true. @return [true, false]

# File lib/mongo/functional/uri_parser.rb, line 207
def connect?
  connect != false
end
connection(extra_opts={}, legacy = false, sharded = false) click to toggle source

Create a Mongo::MongoClient or a Mongo::MongoReplicaSetClient based on the URI.

@note Don't confuse this with attribute getter method connect.

@return [MongoClient,MongoReplicaSetClient]

# File lib/mongo/functional/uri_parser.rb, line 180
def connection(extra_opts={}, legacy = false, sharded = false)
  opts = connection_options.merge!(extra_opts)
  if(legacy)
    if replicaset?
      ReplSetConnection.new(node_strings, opts)
    else
      Connection.new(host, port, opts)
    end
  else
    if sharded
      MongoShardedClient.new(node_strings, opts)
    elsif replicaset?
      MongoReplicaSetClient.new(node_strings, opts)
    else
      MongoClient.new(host, port, opts)
    end
  end
end
connection_options() click to toggle source

Options that can be passed to Mongo::MongoClient.new or Mongo::MongoReplicaSetClient.new @return [Hash]

# File lib/mongo/functional/uri_parser.rb, line 234
def connection_options
  opts = {}

  if @wtimeout
    warn "Using wtimeout in a URI is deprecated, please use wtimeoutMS. It will be removed in v2.0."
    opts[:wtimeout] = @wtimeout
  end
  opts[:wtimeout] = @wtimeoutms if @wtimeoutms

  opts[:w]     = 1 if @safe
  opts[:w]     = @w if @w
  opts[:j]     = @journal if @journal
  opts[:fsync] = @fsync if @fsync

  opts[:connect_timeout] = @connecttimeoutms if @connecttimeoutms
  opts[:op_timeout]      = @sockettimeoutms if @sockettimeoutms
  opts[:pool_size]       = @pool_size if @pool_size
  opts[:read]            = @readpreference if @readpreference

  if @slaveok && !@readpreference
    unless replicaset?
      opts[:slave_ok] = true
    else
      opts[:read] = :secondary_preferred
    end
  end

  if replicaset.is_a?(String)
    opts[:name] = replicaset
  end

  opts[:db_name] = @db_name if @db_name
  opts[:auths]   = @auths if @auths
  opts[:ssl]     = @ssl if @ssl
  opts[:connect] = connect?

  opts
end
direct?() click to toggle source

Whether this represents a direct connection.

@note Specifying :connect => 'direct' has no effect… other than to raise an exception if other variables suggest a replicaset.

@return [true,false]

# File lib/mongo/functional/uri_parser.rb, line 216
def direct?
  !replicaset?
end
host() click to toggle source

For direct connections, the host of the (only) node. @return [String]

# File lib/mongo/functional/uri_parser.rb, line 222
def host
  nodes[0][0]
end
node_strings() click to toggle source
# File lib/mongo/functional/uri_parser.rb, line 273
def node_strings
  nodes.map { |node| node.join(':') }
end
port() click to toggle source

For direct connections, the port of the (only) node. @return [Integer]

# File lib/mongo/functional/uri_parser.rb, line 228
def port
  nodes[0][1].to_i
end
replicaset?() click to toggle source

Whether this represents a replica set. @return [true,false]

# File lib/mongo/functional/uri_parser.rb, line 201
def replicaset?
  replicaset.is_a?(String) || nodes.length > 1
end

Private Instance Methods

parse_hosts(uri_without_protocol) click to toggle source
# File lib/mongo/functional/uri_parser.rb, line 279
def parse_hosts(uri_without_protocol)
  @nodes = []
  @auths = Set.new

  unless matches = MONGODB_URI_MATCHER.match(uri_without_protocol)
    raise MongoArgumentError,
      "MongoDB URI must match this spec: #{MONGODB_URI_SPEC}"
  end

  user_info = matches[2].split(':') if matches[2]
  host_info = matches[3].split(',')
  @db_name  = matches[8]

  host_info.each do |host|
    if host[0,1] == '['
      host, port = host.split(']:') << MongoClient::DEFAULT_PORT
      host = host.end_with?(']') ? host[1...-1] : host[1..-1]
    else
      host, port = host.split(':') << MongoClient::DEFAULT_PORT
    end
    unless port.to_s =~ /^\d+$/
      raise MongoArgumentError,
        "Invalid port #{port}; port must be specified as digits."
    end
    @nodes << [host, port.to_i]
  end

  if @nodes.empty?
    raise MongoArgumentError,
      "No nodes specified. Please ensure that you've provided at " +
      "least one node."
  end

  # no user info to parse, exit here
  return unless user_info

  # check for url encoding for username and password
  username, password = user_info
  if user_info.size > 2 ||
     (username && username.include?('@')) ||
     (password && password.include?('@'))

    raise MongoArgumentError,
      "The characters ':' and '@' in a username or password " +
      "must be escaped (RFC 2396)."
  end

  # if username exists, proceed adding to auth set
  unless username.nil? || username.empty?
    auth = Authentication.validate_credentials({
      :db_name   => @db_name,
      :username  => URI.unescape(username),
      :password  => password ? URI.unescape(password) : nil,
      :source    => @authsource,
      :mechanism => @authmechanism
    })
    auth[:extra] = @canonicalizehostname ? { :canonicalize_host_name => @canonicalizehostname } : {}
    auth[:extra].merge!(:gssapi_service_name => @gssapiservicename) if @gssapiservicename
    @auths << auth
  end
end
parse_options(string_opts) click to toggle source

This method uses the lambdas defined in OPT_VALID and OPT_CONV to validate and convert the given options.

# File lib/mongo/functional/uri_parser.rb, line 343
def parse_options(string_opts)
  # initialize instance variables for available options
  OPT_VALID.keys.each { |k| instance_variable_set("@#{k}", nil) }

  string_opts ||= ''

  return if string_opts.empty?

  if string_opts.include?(';') and string_opts.include?('&')
    raise MongoArgumentError, 'must not mix URL separators ; and &'
  end

  opts = CGI.parse(string_opts).inject({}) do |memo, (key, value)|
    value = value.first
    key_sym = key.downcase.to_sym
    memo[key_sym] = OPT_CASE_SENSITIVE.include?(key_sym) ? value.strip : value.strip.downcase
    memo
  end

  opts.each do |key, value|
    if !OPT_ATTRS.include?(key)
      raise MongoArgumentError, "Invalid Mongo URI option #{key}"
    end
    if OPT_VALID[key].call(value)
      instance_variable_set("@#{key}", OPT_CONV[key].call(value))
    else
      raise MongoArgumentError, "Invalid value #{value.inspect} for #{key}: #{OPT_ERR[key]}"
    end
  end
end
validate_connect() click to toggle source
# File lib/mongo/functional/uri_parser.rb, line 374
def validate_connect
  if replicaset? and @connect == 'direct'
    # Make sure the user doesn't specify something contradictory
    raise MongoArgumentError, "connect=direct conflicts with setting a replicaset name"
  end
end