class Mongo::URI
The URI class provides a way for users to parse the MongoDB uri as defined in the connection string format spec.
docs.mongodb.org/manual/reference/connection-string/
@example Use the uri string to make a client connection.
uri = URI.new('mongodb://localhost:27017') client = Client.new(uri.server, uri.options) client.login(uri.credentials) client[uri.database]
@since 2.0.0
Constants
- AUTH_DELIM
The character delimiting auth credentials.
@since 2.1.0
- AUTH_MECH_MAP
Map of URI authentication mechanisms to ruby driver mechanisms
@since 2.0.0
- AUTH_USER_PWD_DELIM
The character separating a username from the password.
@since 2.1.0
- DATABASE_DELIM
The character delimiting a database.
@since 2.1.0
- FORMAT
MongoDB URI format specification.
@since 2.0.0
- HELP
MongoDB URI (connection string) documentation url
@since 2.0.0
- HOST_DELIM
The character delimiting hosts.
@since 2.1.0
- HOST_PORT_DELIM
The character separating a host and port.
@since 2.1.0
- INDIV_URI_OPTS_DELIM
The character delimiting multiple options.
@since 2.1.0
- INVALID_HOST
Error details for a missing host.
@since 2.1.0
- INVALID_OPTS_DELIM
Error details for providing options without a database delimiter.
@since 2.1.0
- INVALID_OPTS_VALUE_DELIM
Error details for an invalid options format.
@since 2.1.0
- INVALID_PORT
Error details for an invalid port.
@since 2.1.0
- INVALID_SCHEME
Error details for an invalid scheme.
@since 2.1.0
- READ_MODE_MAP
Map of URI read preference modes to ruby driver read preference modes
@since 2.0.0
- REPEATABLE_OPTIONS
Options that are allowed to appear more than once in the uri.
@since 2.1.0
- SCHEME
The mongodb connection string scheme.
@since 2.0.0
- UNESCAPED_DATABASE
Error details for a non-urlencoded auth databsae name.
@since 2.1.0
- UNESCAPED_UNIX_SOCKET
Error details for a non-urlencoded unix socket path.
@since 2.1.0
- UNESCAPED_USER_PWD
Error details for an non-urlencoded user name or password.
@since 2.1.0
- UNIX_SOCKET
Unix socket suffix.
@since 2.1.0
- UNSAFE
Unsafe characters that must be urlencoded.
@since 2.1.0
- URI_OPTION_MAP
Hash for storing map of URI option parameters to conversion strategies
- URI_OPTS_DELIM
The character delimiting options.
@since 2.1.0
- URI_OPTS_VALUE_DELIM
The character delimiting an option and its value.
@since 2.1.0
Attributes
The uri parser object options.
@since 2.0.0
The servers specified in the uri.
@since 2.0.0
The options specified in the uri.
@since 2.1.0
Public Class Methods
Create the new uri from the provided string.
@example Create the new URI.
URI.new('mongodb://localhost:27017')
@param [ String ] string The uri string. @param [ Hash ] options The options.
@raise [ Error::InvalidURI ] If the uri does not match the spec.
@since 2.0.0
# File lib/mongo/uri.rb, line 193 def initialize(string, options = {}) @string = string @options = options _, scheme, remaining = @string.partition(SCHEME) raise_invalid_error!(INVALID_SCHEME) unless scheme == SCHEME setup!(remaining) end
Private Class Methods
Simple internal dsl to register a MongoDB URI option in the URI_OPTION_MAP.
@param uri_key [String] The MongoDB URI option to register. @param name [Symbol] The name of the option in the driver. @param extra [Hash] Extra options.
* :group [Symbol] Nested hash where option will go. * :type [Symbol] Name of function to transform value.
# File lib/mongo/uri.rb, line 355 def self.uri_option(uri_key, name, extra = {}) URI_OPTION_MAP[uri_key] = { :name => name }.merge(extra) end
Public Instance Methods
Gets the options hash that needs to be passed to a Mongo::Client on instantiation, so we don't have to merge the 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.0.0
# File lib/mongo/uri.rb, line 211 def client_options opts = uri_options.merge(:database => database) @user ? opts.merge(credentials) : opts end
Get the credentials provided in the URI.
@example Get the credentials.
uri.credentials
@return [ Hash ] The credentials.
* :user [ String ] The user. * :password [ String ] The provided password.
@since 2.0.0
# File lib/mongo/uri.rb, line 226 def credentials { :user => @user, :password => @password } end
Get the database provided in the URI.
@example Get the database.
uri.database
@return [String] The database.
@since 2.0.0
# File lib/mongo/uri.rb, line 238 def database @database ? @database : Database::ADMIN end
Private Instance Methods
Adds an option to the uri options hash via the supplied strategy.
Acquires a target for the option based on group. Transforms the value. Merges the option into the target.
@param strategy [Symbol] The strategy for this option. @param value [String] The value of the option. @param #uri_options [Hash] The base option target.
# File lib/mongo/uri.rb, line 475 def add_uri_option(strategy, value, uri_options) target = select_target(uri_options, strategy[:group]) value = apply_transform(value, strategy[:type]) merge_uri_option(target, value, strategy[:name]) end
Applies URI value transformation by either using the default cast or a transformation appropriate for the given type.
@param value [String] The value to be transformed. @param type [Symbol] The transform method.
# File lib/mongo/uri.rb, line 421 def apply_transform(value, type = nil) if type send(type, value) else cast(value) end end
Authentication mechanism transformation.
@param value [String] The authentication mechanism.
@return [Symbol] The transformed authentication mechanism.
# File lib/mongo/uri.rb, line 505 def auth_mech(value) AUTH_MECH_MAP[value.upcase] end
Auth mechanism properties extractor.
@param value [ String ] The auth mechanism properties string.
@return [ Hash ] The auth mechanism properties hash.
# File lib/mongo/uri.rb, line 541 def auth_mech_props(value) properties = hash_extractor(value) if properties[:canonicalize_host_name] properties.merge!(canonicalize_host_name: properties[:canonicalize_host_name] == 'true') end properties end
Auth source transformation, either db string or :external.
@param value [String] Authentication source.
@return [String] If auth source is database name. @return [:external] If auth source is external authentication.
# File lib/mongo/uri.rb, line 496 def auth_source(value) value == '$external' ? :external : decode(value) end
Casts option values that do not have a specifically provided transformation to the appropriate type.
@param value [String] The value to be cast.
@return [true, false, Fixnum, Symbol] The cast value.
# File lib/mongo/uri.rb, line 404 def cast(value) if value == 'true' true elsif value == 'false' false elsif value =~ /[\d]/ value.to_i else decode(value).to_sym end end
# File lib/mongo/uri.rb, line 341 def decode(value) ::URI::DEFAULT_PARSER.unescape(value) end
# File lib/mongo/uri.rb, line 250 def extract_db_opts!(string) db_opts, _, creds_hosts = string.reverse.partition(DATABASE_DELIM) db_opts, creds_hosts = creds_hosts, db_opts if creds_hosts.empty? if db_opts.empty? && creds_hosts.include?(URI_OPTS_DELIM) raise_invalid_error!(INVALID_OPTS_DELIM) end [ creds_hosts, db_opts ].map { |s| s.reverse } end
Extract values from the string and put them into a nested hash.
@param value [ String ] The string to build a hash from.
@return [ Hash ] The hash built from the string.
# File lib/mongo/uri.rb, line 568 def hash_extractor(value) value.split(',').reduce({}) do |set, tag| k, v = tag.split(':') set.merge(decode(k).downcase.to_sym => decode(v)) end end
Merges a new option into the target.
If the option exists at the target destination the merge will be an addition.
Specifically required to append an additional tag set to the array of tag sets without overwriting the original.
@param target [Hash] The destination. @param value [Object] The value to be merged. @param name [Symbol] The name of the option.
# File lib/mongo/uri.rb, line 454 def merge_uri_option(target, value, name) if target.key?(name) if REPEATABLE_OPTIONS.include?(name) target[name] += value else log_warn("Repeated option key: #{name}.") end else target.merge!(name => value) end end
Ruby's convention is to provide timeouts in seconds, not milliseconds and to use fractions where more precision is necessary. The connection string options are always in MS so we provide an easy conversion type.
@param [ Integer ] value The millisecond value.
@return [ Float ] The seconds value.
@since 2.0.0
# File lib/mongo/uri.rb, line 559 def ms_convert(value) value.to_f / 1000 end
# File lib/mongo/uri.rb, line 259 def parse_creds_hosts!(string) hosts, creds = split_creds_hosts(string) @servers = parse_servers!(hosts) @user = parse_user!(creds) @password = parse_password!(creds) end
# File lib/mongo/uri.rb, line 307 def parse_database!(string) raise_invalid_error!(UNESCAPED_DATABASE) if string =~ UNSAFE decode(string) if string.length > 0 end
# File lib/mongo/uri.rb, line 272 def parse_db_opts!(string) auth_db, _, uri_opts = string.partition(URI_OPTS_DELIM) @uri_options = Options::Redacted.new(parse_uri_options!(uri_opts)) @database = parse_database!(auth_db) end
# File lib/mongo/uri.rb, line 300 def parse_password!(string) if (string && pwd = string.partition(AUTH_USER_PWD_DELIM)[2]) raise_invalid_error!(UNESCAPED_USER_PWD) if pwd =~ UNSAFE decode(pwd) if pwd.length > 0 end end
# File lib/mongo/uri.rb, line 318 def parse_servers!(string) raise_invalid_error!(INVALID_HOST) unless string.size > 0 string.split(HOST_DELIM).reduce([]) do |servers, host| if host[0] == '[' if host.index(']:') h, p = host.split(']:') validate_port_string!(p) end elsif host.index(HOST_PORT_DELIM) h, _, p = host.partition(HOST_PORT_DELIM) raise_invalid_error!(INVALID_HOST) unless h.size > 0 validate_port_string!(p) elsif host =~ UNIX_SOCKET raise_invalid_error!(UNESCAPED_UNIX_SOCKET) if host =~ UNSAFE end servers << host end end
# File lib/mongo/uri.rb, line 278 def parse_uri_options!(string) return {} unless string string.split(INDIV_URI_OPTS_DELIM).reduce({}) do |uri_options, opt| raise_invalid_error!(INVALID_OPTS_VALUE_DELIM) unless opt.index(URI_OPTS_VALUE_DELIM) key, value = opt.split(URI_OPTS_VALUE_DELIM) strategy = URI_OPTION_MAP[key.downcase] if strategy.nil? log_warn("Unsupported URI option '#{key}' on URI '#{@string}'. It will be ignored.") else add_uri_option(strategy, value, uri_options) end uri_options end end
# File lib/mongo/uri.rb, line 293 def parse_user!(string) if (string && user = string.partition(AUTH_USER_PWD_DELIM)[0]) raise_invalid_error!(UNESCAPED_USER_PWD) if user =~ UNSAFE decode(user) if user.length > 0 end end
# File lib/mongo/uri.rb, line 337 def raise_invalid_error!(details) raise Error::InvalidURI.new(@string, details) end
Read preference mode transformation.
@param value [String] The read mode string value.
@return [Symbol] The read mode symbol.
# File lib/mongo/uri.rb, line 514 def read_mode(value) READ_MODE_MAP[value.downcase] end
Read preference tag set extractor.
@param value [String] The tag set string.
@return [Hash] The tag set hash.
# File lib/mongo/uri.rb, line 532 def read_set(value) hash_extractor(value) end
Selects the output destination for an option.
@param [Hash] #uri_options The base target. @param [Symbol] group Group subtarget.
@return [Hash] The target for the option.
# File lib/mongo/uri.rb, line 435 def select_target(uri_options, group = nil) if group uri_options[group] ||= {} else uri_options end end
# File lib/mongo/uri.rb, line 244 def setup!(remaining) creds_hosts, db_opts = extract_db_opts!(remaining) parse_creds_hosts!(creds_hosts) parse_db_opts!(db_opts) end
# File lib/mongo/uri.rb, line 266 def split_creds_hosts(string) hosts, _, creds = string.reverse.partition(AUTH_DELIM) hosts, creds = creds, hosts if hosts.empty? [ hosts, creds ].map { |s| s.reverse } end
# File lib/mongo/uri.rb, line 312 def validate_port_string!(port) unless port.nil? || (port.length > 0 && port.to_i > 0 && port.to_i <= 65535) raise_invalid_error!(INVALID_PORT) end end