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 = Mongo::URI.new('mongodb://localhost:27017') client = Mongo::Client.new(uri.servers, 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 @deprecated
- 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 @deprecated
- MONGODB_SCHEME
-
The mongodb connection string scheme root.
@since 2.5.0
- MONGODB_SRV_SCHEME
-
The mongodb srv protocol connection string scheme root.
@since 2.5.0
- PERCENT_CHAR
-
Percent sign that must be encoded in user creds.
@since 2.5.1
- 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.In order to follow the
URI
options spec requirement that all instances of ‘tls’ and ‘ssl’ have the same value, we need to keep track of all of the values passed in for those options. Assuming they don’t conflict, they will be condensed to a single value immediately after parsing theURI
.@since 2.1.0
- SCHEME
-
The mongodb connection string scheme.
@deprecated Will be removed in 3.0.
@since 2.0.0
- SCHEME_DELIM
-
Scheme delimiter.
@since 2.5.0
- UNESCAPED_DATABASE
-
Error
details for a non-urlencoded auth database 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_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
Mongo::Options::Redacted
of the options specified in the uri.
@since 2.1.0
Public Class Methods
Source
# File lib/mongo/uri.rb, line 227 def self.get(string, opts = {}) unless string raise Error::InvalidURI.new(string, 'URI must be a string, not nil.') end if string.empty? raise Error::InvalidURI.new(string, 'Cannot parse an empty URI.') end scheme, _, remaining = string.partition(SCHEME_DELIM) case scheme when MONGODB_SCHEME URI.new(string, opts) when MONGODB_SRV_SCHEME SRVProtocol.new(string, opts) else raise Error::InvalidURI.new(string, "Invalid scheme '#{scheme}'. Scheme must be '#{MONGODB_SCHEME}' or '#{MONGODB_SRV_SCHEME}'") end end
Get either a URI
object or a SRVProtocol
URI
object.
@example Get the uri object.
URI.get(string)
@param [ String ] string The URI
to parse. @param [ Hash ] opts The options.
@option options [ Logger
] :logger A custom logger to use.
@return [URI, URI::SRVProtocol
] The uri object.
@since 2.5.0
Source
# File lib/mongo/uri.rb, line 281 def initialize(string, options = {}) unless string raise Error::InvalidURI.new(string, 'URI must be a string, not nil.') end if string.empty? raise Error::InvalidURI.new(string, 'Cannot parse an empty URI.') end @string = string @options = options parsed_scheme, _, remaining = string.partition(SCHEME_DELIM) unless parsed_scheme == scheme raise_invalid_error!("Invalid scheme '#{parsed_scheme}'. Scheme must be '#{MONGODB_SCHEME}'. Use URI#get to parse SRV URIs.") end if remaining.empty? raise_invalid_error!('No hosts in the URI') end parse!(remaining) validate_uri_options! end
Create the new uri from the provided string.
@example Create the new URI
.
URI.new('mongodb://localhost:27017')
@param [ String ] string The URI
to parse. @param [ Hash ] options The options.
@option options [ Logger
] :logger A custom logger to use.
@raise [ Error::InvalidURI
] If the uri does not match the spec.
@since 2.0.0
Public Instance Methods
Source
# File lib/mongo/uri.rb, line 256 def client_options opts = uri_options.tap do |opts| opts[:database] = @database if @database end @user ? opts.merge(credentials) : opts end
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 [ Mongo::Options::Redacted
] The options passed to the Mongo::Client
@since 2.0.0
Source
# File lib/mongo/uri.rb, line 312 def credentials { :user => @user, :password => @password } 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
Source
# File lib/mongo/uri.rb, line 324 def database @database ? @database : Database::ADMIN end
Get the database provided in the URI
.
@example Get the database.
uri.database
@return [String] The database.
@since 2.0.0
Private Instance Methods
Source
# File lib/mongo/uri.rb, line 454 def decode(value) ::URI::DEFAULT_PARSER.unescape(value) end
Source
# File lib/mongo/uri.rb, line 458 def encode(value) CGI.escape(value).gsub('+', '%20') end
Source
# File lib/mongo/uri.rb, line 382 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
Source
# File lib/mongo/uri.rb, line 391 def options_mapper @options_mapper ||= OptionsMapper.new( logger: @options[:logger], ) end
Source
# File lib/mongo/uri.rb, line 334 def parse!(remaining) hosts_and_db, options = remaining.split('?', 2) if options && options.index('?') raise_invalid_error!("Options contain an unescaped question mark (?), or the database name contains a question mark and was not escaped") end if options && !hosts_and_db.index('/') raise_invalid_error!("MongoDB URI must have a slash (/) after the hosts if options are given") end hosts, db = hosts_and_db.split('/', 2) if db && db.index('/') raise_invalid_error!("Database name contains an unescaped slash (/): #{db}") end if hosts.index('@') creds, hosts = hosts.split('@', 2) if hosts.empty? raise_invalid_error!("Empty hosts list") end if hosts.index('@') raise_invalid_error!("Unescaped @ in auth info") end end unless hosts.length > 0 raise_invalid_error!("Missing host; at least one must be provided") end @servers = hosts.split(',').map do |host| if host.empty? raise_invalid_error!('Empty host given in the host list') end decode(host).tap do |host| validate_address_str!(host) end end @user = parse_user!(creds) @password = parse_password!(creds) @uri_options = Options::Redacted.new(parse_uri_options!(options)) if db @database = parse_database!(db) end rescue Error::InvalidAddress => e raise_invalid_error!(e.message) end
Source
# File lib/mongo/uri.rb, line 441 def parse_database!(string) raise_invalid_error!(UNESCAPED_DATABASE) if string =~ UNSAFE decode(string) if string.length > 0 end
Source
# File lib/mongo/uri.rb, line 428 def parse_password!(string) if (string && pwd = string.partition(AUTH_USER_PWD_DELIM)[2]) if pwd.length > 0 raise_invalid_error!(UNESCAPED_USER_PWD) if pwd =~ UNSAFE pwd_decoded = decode(pwd) if pwd_decoded =~ PERCENT_CHAR && encode(pwd_decoded) != pwd raise_invalid_error!(UNESCAPED_USER_PWD) end pwd_decoded end end end
Source
# File lib/mongo/uri.rb, line 397 def parse_uri_options!(string) uri_options = {} unless string return uri_options end string.split('&').each do |option_str| if option_str.empty? next end key, value = option_str.split('=', 2) if value.nil? raise_invalid_error!("Option #{key} has no value") end key = decode(key) value = decode(value) options_mapper.add_uri_option(key, value, uri_options) end uri_options end
Source
# File lib/mongo/uri.rb, line 417 def parse_user!(string) if (string && user = string.partition(AUTH_USER_PWD_DELIM)[0]) raise_invalid_error!(UNESCAPED_USER_PWD) if user =~ UNSAFE user_decoded = decode(user) if user_decoded =~ PERCENT_CHAR && encode(user_decoded) != user raise_invalid_error!(UNESCAPED_USER_PWD) end user_decoded end end
Source
# File lib/mongo/uri.rb, line 446 def raise_invalid_error!(details) raise Error::InvalidURI.new(@string, details, FORMAT) end
Source
# File lib/mongo/uri.rb, line 450 def raise_invalid_error_no_fmt!(details) raise Error::InvalidURI.new(@string, details) end
Source
# File lib/mongo/uri.rb, line 462 def validate_uri_options! # The URI options spec requires that we raise an error if there are conflicting values of # 'tls' and 'ssl'. In order to fulfill this, we parse the values of each instance into an # array; assuming all values in the array are the same, we replace the array with that value. unless uri_options[:ssl].nil? || uri_options[:ssl].empty? unless uri_options[:ssl].uniq.length == 1 raise_invalid_error_no_fmt!("all instances of 'tls' and 'ssl' must have the same value") end uri_options[:ssl] = uri_options[:ssl].first end # Check for conflicting TLS insecure options. unless uri_options[:ssl_verify].nil? unless uri_options[:ssl_verify_certificate].nil? raise_invalid_error_no_fmt!("'tlsInsecure' and 'tlsAllowInvalidCertificates' cannot both be specified") end unless uri_options[:ssl_verify_hostname].nil? raise_invalid_error_no_fmt!("tlsInsecure' and 'tlsAllowInvalidHostnames' cannot both be specified") end unless uri_options[:ssl_verify_ocsp_endpoint].nil? raise_invalid_error_no_fmt!("tlsInsecure' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") end end unless uri_options[:ssl_verify_certificate].nil? unless uri_options[:ssl_verify_ocsp_endpoint].nil? raise_invalid_error_no_fmt!("tlsAllowInvalidCertificates' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") end end # Since we know that the only URI option that sets :ssl_cert is # "tlsCertificateKeyFile", any value set for :ssl_cert must also be set # for :ssl_key. if uri_options[:ssl_cert] uri_options[:ssl_key] = uri_options[:ssl_cert] end if uri_options[:write_concern] && !uri_options[:write_concern].empty? begin WriteConcern.get(uri_options[:write_concern]) rescue Error::InvalidWriteConcern => e raise_invalid_error_no_fmt!("#{e.class}: #{e}") end end if uri_options[:direct_connection] if uri_options[:connect] && uri_options[:connect].to_s != 'direct' raise_invalid_error_no_fmt!("directConnection=true cannot be used with connect=#{uri_options[:connect]}") end if servers.length > 1 raise_invalid_error_no_fmt!("directConnection=true cannot be used with multiple seeds") end elsif uri_options[:direct_connection] == false && uri_options[:connect].to_s == 'direct' raise_invalid_error_no_fmt!("directConnection=false cannot be used with connect=direct") end end