Class: Mongo::URI
| Relationships & Source Files | |
| Namespace Children | |
|
Classes:
| |
| Extension / Inclusion / Inheritance Descendants | |
|
Subclasses:
|
|
| Super Chains via Extension / Inclusion / Inheritance | |
|
Instance Chain:
self,
Address::Validator,
Loggable
|
|
| Inherits: | Object |
| Defined in: | lib/mongo/uri.rb, lib/mongo/uri/options_mapper.rb, lib/mongo/uri/srv_protocol.rb |
Overview
The URI class provides a way for users to parse the MongoDB uri as defined in the connection string format spec.
Constant Summary
-
AUTH_DELIM =
# File 'lib/mongo/uri.rb', line 137
The character delimiting auth credentials.
'@' -
AUTH_MECH_MAP =
# File 'lib/mongo/uri.rb', line 194
Map of
URIauthentication mechanisms to Ruby driver mechanisms{ 'GSSAPI' => :gssapi, 'MONGODB-AWS' => :aws, # MONGODB-CR is deprecated and will be removed in driver version 3.0 'MONGODB-CR' => :mongodb_cr, 'MONGODB-X509' => :mongodb_x509, 'PLAIN' => :plain, 'SCRAM-SHA-1' => :scram, 'SCRAM-SHA-256' => :scram256, }.freeze -
AUTH_USER_PWD_DELIM =
# File 'lib/mongo/uri.rb', line 132
The character separating a username from the password.
':' -
DATABASE_DELIM =
# File 'lib/mongo/uri.rb', line 111
The character delimiting a database.
'/' -
FORMAT =
# File 'lib/mongo/uri.rb', line 75
MongoDB URI format specification.
'mongodb://[username:password@]host1[:port1][,host2[:port2]' + ',...[,hostN[:portN]]][/[database][?options]]'
-
HELP =
# File 'lib/mongo/uri.rb', line 81
MongoDB URI (connection string) documentation url
'https://www.mongodb.com/docs/manual/reference/connection-string/' -
HOST_DELIM =
# File 'lib/mongo/uri.rb', line 101
The character delimiting hosts.
',' -
HOST_PORT_DELIM =
# File 'lib/mongo/uri.rb', line 106
The character separating a host and port.
':' -
INDIV_URI_OPTS_DELIM =
# File 'lib/mongo/uri.rb', line 122Deprecated.
The character delimiting multiple options.
'&' -
INVALID_HOST =
# File 'lib/mongo/uri.rb', line 173
Errordetails for a missing host.'Missing host; at least one must be provided.' -
INVALID_OPTS_DELIM =
# File 'lib/mongo/uri.rb', line 168
Errordetails for providing options without a database delimiter."Database delimiter '#{DATABASE_DELIM}' must be present if options are specified." -
INVALID_OPTS_VALUE_DELIM =
# File 'lib/mongo/uri.rb', line 147
Errordetails for an invalid options format.'Options and their values must be delimited' + " by '#{URI_OPTS_VALUE_DELIM}'"
-
INVALID_PORT =
# File 'lib/mongo/uri.rb', line 178
Errordetails for an invalid port.'Invalid port. Port must be an integer greater than 0 and less than 65536' -
INVALID_SCHEME =
# File 'lib/mongo/uri.rb', line 70Deprecated.
Errordetails for an invalid scheme."Invalid scheme. Scheme must be '#{MONGODB_SCHEME}' or '#{MONGODB_SRV_SCHEME}'" -
MONGODB_SCHEME =
# File 'lib/mongo/uri.rb', line 59
The mongodb connection string scheme root.
'mongodb' -
MONGODB_SRV_SCHEME =
# File 'lib/mongo/uri.rb', line 64
The mongodb srv protocol connection string scheme root.
'mongodb+srv' -
PERCENT_CHAR =
# File 'lib/mongo/uri.rb', line 91
Percent sign that must be encoded in user creds.
/%/ -
READ_MODE_MAP =
# File 'lib/mongo/uri.rb', line 183
Map of
URIread preference modes to Ruby driver read preference modes{ 'primary' => :primary, 'primarypreferred' => :primary_preferred, 'secondary' => :secondary, 'secondarypreferred' => :secondary_preferred, 'nearest' => :nearest }.freeze -
REPEATABLE_OPTIONS =
# File 'lib/mongo/uri.rb', line 216
Optionsthat are allowed to appear more than once in the uri.In order to follow the
URIoptions 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.%i[tag_sets ssl] -
SCHEME =
# File 'lib/mongo/uri.rb', line 54Deprecated.
Will be removed in 3.0.
The mongodb connection string scheme.
'mongodb://' -
SCHEME_DELIM =
# File 'lib/mongo/uri.rb', line 142
Scheme delimiter.
'://' -
SERVER_MONITORING_MODES =
# File 'lib/mongo/uri.rb', line 206
Valid values for the serverMonitoringMode
URIoption.%w[stream poll auto].freeze
-
UNESCAPED_DATABASE =
# File 'lib/mongo/uri.rb', line 163
Errordetails for a non-urlencoded auth database name.'Auth database must be urlencoded.' -
UNESCAPED_UNIX_SOCKET =
# File 'lib/mongo/uri.rb', line 158
Errordetails for a non-urlencoded unix socket path.'UNIX domain sockets must be urlencoded.' -
UNESCAPED_USER_PWD =
# File 'lib/mongo/uri.rb', line 153
Errordetails for an non-urlencoded user name or password.'User name and password must be urlencoded.' -
UNIX_SOCKET =
# File 'lib/mongo/uri.rb', line 96
Unix socket suffix.
/.sock/ -
UNSAFE =
# File 'lib/mongo/uri.rb', line 86
Unsafe characters that must be urlencoded.
%r{[:/@]} -
URI_OPTS_DELIM =
# File 'lib/mongo/uri.rb', line 116
The character delimiting options.
'?' -
URI_OPTS_VALUE_DELIM =
# File 'lib/mongo/uri.rb', line 127
The character delimiting an option and its value.
'='
Loggable - Included
Class Method Summary
-
.get(string, opts = {}) ⇒ URI, URI::SRVProtocol
Get either a
URIobject or aSRVProtocolURI object. -
.new(string, options = {}) ⇒ URI
constructor
Create the new uri from the provided string.
Instance Attribute Summary
-
#options
readonly
The uri parser object options.
-
#servers
readonly
The servers specified in the uri.
-
#uri_options
readonly
Mongo::Options::Redacted of the options specified in the uri.
Instance Method Summary
-
#client_options ⇒ Mongo::Options::Redacted
Gets the options hash that needs to be passed to a
Clienton instantiation, so we don’t have to merge the credentials and database in at that point - we only have a single point here. -
#credentials ⇒ Hash
Get the credentials provided in the
URI. -
#database ⇒ String
Get the database provided in the
URI. - #srv_records
-
#to_s ⇒ String
Get the uri as a string.
- #decode(value) private
- #encode(value) private
- #options_mapper private
- #parse!(remaining) private
- #parse_database!(string) private
- #parse_password!(string) private
- #parse_uri_options!(string) private
- #parse_user!(string) private
- #raise_invalid_error!(details) private
- #raise_invalid_error_no_fmt!(details) private
-
#reconstruct_uri ⇒ String
private
Reconstruct the
URIfrom its parts. - #scheme private
- #validate_uri_options! private
Address::Validator - Included
| #validate_address_str! | Takes an address string in ipv4/ipv6/hostname/socket path format and validates its format. |
| #validate_hostname! | Validates format of the hostname, in particular for further use as the origin in same origin verification. |
| #validate_port_str! | |
Loggable - Included
| #log_debug | Convenience method to log debug messages with the standard prefix. |
| #log_error | Convenience method to log error messages with the standard prefix. |
| #log_fatal | Convenience method to log fatal messages with the standard prefix. |
| #log_info | Convenience method to log info messages with the standard prefix. |
| #log_warn | Convenience method to log warn messages with the standard prefix. |
| #logger | Get the logger instance. |
| #_mongo_log_prefix, #format_message | |
Constructor Details
.new(string, options = {}) ⇒ URI
Create the new uri from the provided string.
# File 'lib/mongo/uri.rb', line 282
def initialize(string, = {}) raise Error::InvalidURI.new(string, 'URI must be a string, not nil.') unless string raise Error::InvalidURI.new(string, 'Cannot parse an empty URI.') if string.empty? @string = string @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 raise_invalid_error!('No hosts in the URI') if remaining.empty? parse!(remaining) end
Class Method Details
.get(string, opts = {}) ⇒ URI, URI::SRVProtocol
Get either a URI object or a URI::SRVProtocol URI object.
# File 'lib/mongo/uri.rb', line 231
def self.get(string, opts = {}) raise Error::InvalidURI.new(string, 'URI must be a string, not nil.') unless string raise Error::InvalidURI.new(string, 'Cannot parse an empty URI.') if string.empty? scheme, = 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
Instance Attribute Details
#options (readonly)
The uri parser object options.
# File 'lib/mongo/uri.rb', line 37
attr_reader :
#servers (readonly)
The servers specified in the uri.
# File 'lib/mongo/uri.rb', line 47
attr_reader :servers
#uri_options (readonly)
Mongo::Options::Redacted of the options specified in the uri.
# File 'lib/mongo/uri.rb', line 42
attr_reader :
Instance Method Details
#client_options ⇒ Mongo::Options::Redacted
Gets the options hash that needs to be passed to a 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.
# File 'lib/mongo/uri.rb', line 257
def opts = .tap do |opts| opts[:database] = @database if @database end @user ? opts.merge(credentials) : opts end
#credentials ⇒ Hash
Get the credentials provided in the URI.
# File 'lib/mongo/uri.rb', line 307
def credentials { user: @user, password: @password } end
#database ⇒ String
Get the database provided in the URI.
#decode(value) (private)
# File 'lib/mongo/uri.rb', line 451
def decode(value) ::URI::DEFAULT_PARSER.unescape(value) end
#encode(value) (private)
# File 'lib/mongo/uri.rb', line 455
def encode(value) CGI.escape(value).gsub('+', '%20') end
#options_mapper (private)
# File 'lib/mongo/uri.rb', line 398
def @options_mapper ||= OptionsMapper.new( logger: @options[:logger] ) end
#parse!(remaining) (private)
# File 'lib/mongo/uri.rb', line 366
def parse!(remaining) hosts_and_db, = remaining.split('?', 2) if && .index('?') raise_invalid_error!('Options contain an unescaped question mark (?), or the database name contains a question mark and was not escaped') end hosts, db = hosts_and_db.split('/', 2) raise_invalid_error!("Database name contains an unescaped slash (/): #{db}") if db && db.index('/') if hosts.index('@') creds, hosts = hosts.split('@', 2) raise_invalid_error!('Empty hosts list') if hosts.empty? raise_invalid_error!('Unescaped @ in auth info') if hosts.index('@') end raise_invalid_error!('Missing host; at least one must be provided') unless hosts.length > 0 @servers = hosts.split(',').map do |host| raise_invalid_error!('Empty host given in the host list') if host.empty? decode(host).tap do |host| validate_address_str!(host) end end @user = parse_user!(creds) @password = parse_password!(creds) @uri_options = Options::Redacted.new(()) @database = parse_database!(db) if db rescue Error::InvalidAddress => e raise_invalid_error!(e.) end
#parse_database!(string) (private)
# File 'lib/mongo/uri.rb', line 438
def parse_database!(string) raise_invalid_error!(UNESCAPED_DATABASE) if UNSAFE.match?(string) decode(string) if string.length > 0 end
#parse_password!(string) (private)
# File 'lib/mongo/uri.rb', line 429
def parse_password!(string) if string && (pwd = string.partition(AUTH_USER_PWD_DELIM)[2]) && (pwd.length > 0) raise_invalid_error!(UNESCAPED_USER_PWD) if UNSAFE.match?(pwd) pwd_decoded = decode(pwd) raise_invalid_error!(UNESCAPED_USER_PWD) if pwd_decoded =~ PERCENT_CHAR && encode(pwd_decoded) != pwd pwd_decoded end end
#parse_uri_options!(string) (private)
# File 'lib/mongo/uri.rb', line 404
def (string) = {} return unless string string.split('&').each do |option_str| next if option_str.empty? key, value = option_str.split('=', 2) raise_invalid_error!("Option #{key} has no value") if value.nil? key = decode(key) value = decode(value) .add_uri_option(key, value, ) end end
#parse_user!(string) (private)
# File 'lib/mongo/uri.rb', line 420
def parse_user!(string) if string && user = string.partition(AUTH_USER_PWD_DELIM)[0] raise_invalid_error!(UNESCAPED_USER_PWD) if UNSAFE.match?(user) user_decoded = decode(user) raise_invalid_error!(UNESCAPED_USER_PWD) if user_decoded =~ PERCENT_CHAR && encode(user_decoded) != user user_decoded end end
#raise_invalid_error!(details) (private)
# File 'lib/mongo/uri.rb', line 443
def raise_invalid_error!(details) raise Error::InvalidURI.new(@string, details, FORMAT) end
#raise_invalid_error_no_fmt!(details) (private)
# File 'lib/mongo/uri.rb', line 447
def raise_invalid_error_no_fmt!(details) raise Error::InvalidURI.new(@string, details) end
#reconstruct_uri ⇒ String (private)
Reconstruct the URI from its parts. Invalid options are dropped and options are converted to camelCase.
# File 'lib/mongo/uri.rb', line 339
def reconstruct_uri servers = @servers.join(',') = .ruby_to_string(@uri_options).map do |k, vs| unless vs.nil? if vs.is_a?(Array) vs.map { |v| "#{k}=#{v}" }.join('&') else "#{k}=#{vs}" end end end.compact.join('&') uri = "#{scheme}#{SCHEME_DELIM}" uri += @user.to_s if @user uri += "#{AUTH_USER_PWD_DELIM}#{@password}" if @password uri += '@' if @user || @password uri += @query_hostname || servers uri += '/' if @database || !.empty? uri += @database.to_s if @database uri += "?#{}" unless .empty? uri end
#scheme (private)
# File 'lib/mongo/uri.rb', line 362
def scheme MONGODB_SCHEME end
#srv_records
# File 'lib/mongo/uri.rb', line 265
def srv_records nil end
#to_s ⇒ String
Get the uri as a string.
# File 'lib/mongo/uri.rb', line 329
def to_s reconstruct_uri end
#validate_uri_options! (private)
# File 'lib/mongo/uri.rb', line 459
def # 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 [:ssl].nil? || [:ssl].empty? unless [:ssl].uniq.length == 1 raise_invalid_error_no_fmt!("all instances of 'tls' and 'ssl' must have the same value") end [:ssl] = [:ssl].first end # Check for conflicting TLS insecure options. unless [:ssl_verify].nil? unless [:ssl_verify_certificate].nil? raise_invalid_error_no_fmt!("'tlsInsecure' and 'tlsAllowInvalidCertificates' cannot both be specified") end unless [:ssl_verify_hostname].nil? raise_invalid_error_no_fmt!("tlsInsecure' and 'tlsAllowInvalidHostnames' cannot both be specified") end unless [:ssl_verify_ocsp_endpoint].nil? raise_invalid_error_no_fmt!("tlsInsecure' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") end end if ![:ssl_verify_certificate].nil? && ![:ssl_verify_ocsp_endpoint].nil? raise_invalid_error_no_fmt!("tlsAllowInvalidCertificates' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") 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. [:ssl_key] = [:ssl_cert] if [:ssl_cert] if [:write_concern] && ![:write_concern].empty? begin WriteConcern.get([:write_concern]) rescue Error::InvalidWriteConcern => e raise_invalid_error_no_fmt!("#{e.class}: #{e}") end end if [:direct_connection] if [:connect] && [:connect].to_s != 'direct' raise_invalid_error_no_fmt!("directConnection=true cannot be used with connect=#{[:connect]}") end raise_invalid_error_no_fmt!('directConnection=true cannot be used with multiple seeds') if servers.length > 1 elsif [:direct_connection] == false && [:connect].to_s == 'direct' raise_invalid_error_no_fmt!('directConnection=false cannot be used with connect=direct') end if [:load_balanced] raise_invalid_error_no_fmt!('loadBalanced=true cannot be used with multiple seeds') if servers.length > 1 if [:direct_connection] raise_invalid_error_no_fmt!('directConnection=true cannot be used with loadBalanced=true') end if [:connect] && [:connect].to_sym == :direct raise_invalid_error_no_fmt!('connect=direct cannot be used with loadBalanced=true') end if [:replica_set] raise_invalid_error_no_fmt!('loadBalanced=true cannot be used with replicaSet option') end end unless is_a?(URI::SRVProtocol) raise_invalid_error_no_fmt!('srvMaxHosts cannot be used on non-SRV URI') if [:srv_max_hosts] raise_invalid_error_no_fmt!('srvServiceName cannot be used on non-SRV URI') if [:srv_service_name] end return unless [:srv_max_hosts] && [:srv_max_hosts] > 0 raise_invalid_error_no_fmt!('srvMaxHosts > 0 cannot be used with replicaSet option') if [:replica_set] return unless [:load_balanced] raise_invalid_error_no_fmt!('srvMaxHosts > 0 cannot be used with loadBalanced=true') end