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 =
The character delimiting auth credentials.
'@'.freeze
-
AUTH_MECH_MAP =
Map of
URI
authentication 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 =
The character separating a username from the password.
':'.freeze
-
DATABASE_DELIM =
The character delimiting a database.
'/'.freeze
-
FORMAT =
MongoDB URI format specification.
'mongodb://[username:password@]host1[:port1][,host2[:port2]' + ',...[,hostN[:portN]]][/[database][?options]]'.freeze
-
HELP =
MongoDB URI (connection string) documentation url
'https://www.mongodb.com/docs/manual/reference/connection-string/'.freeze
-
HOST_DELIM =
The character delimiting hosts.
','.freeze
-
HOST_PORT_DELIM =
The character separating a host and port.
':'.freeze
-
INDIV_URI_OPTS_DELIM =
Deprecated.
The character delimiting multiple options.
'&'.freeze
-
INVALID_HOST =
Error
details for a missing host."Missing host; at least one must be provided.".freeze
-
INVALID_OPTS_DELIM =
Error
details for providing options without a database delimiter."Database delimiter '#{DATABASE_DELIM}' must be present if options are specified.".freeze
-
INVALID_OPTS_VALUE_DELIM =
Error
details for an invalid options format."Options and their values must be delimited" + " by '#{URI_OPTS_VALUE_DELIM}'".freeze
-
INVALID_PORT =
Error
details for an invalid port."Invalid port. Port must be an integer greater than 0 and less than 65536".freeze
-
INVALID_SCHEME =
Deprecated.
Error
details for an invalid scheme."Invalid scheme. Scheme must be '#{MONGODB_SCHEME}' or '#{MONGODB_SRV_SCHEME}'".freeze
-
MONGODB_SCHEME =
The mongodb connection string scheme root.
'mongodb'.freeze
-
MONGODB_SRV_SCHEME =
The mongodb srv protocol connection string scheme root.
'mongodb+srv'.freeze
-
PERCENT_CHAR =
Percent sign that must be encoded in user creds.
/\%/
-
READ_MODE_MAP =
Map of
URI
read preference modes to Ruby driver read preference modes{ 'primary' => :primary, 'primarypreferred' => :primary_preferred, 'secondary' => :secondary, 'secondarypreferred' => :secondary_preferred, 'nearest' => :nearest }.freeze
-
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
.[ :tag_sets, :ssl ]
-
SCHEME =
Deprecated.
Will be removed in 3.0.
The mongodb connection string scheme.
'mongodb://'.freeze
-
SCHEME_DELIM =
Scheme delimiter.
'://'.freeze
-
UNESCAPED_DATABASE =
Error
details for a non-urlencoded auth database name."Auth database must be urlencoded.".freeze
-
UNESCAPED_UNIX_SOCKET =
Error
details for a non-urlencoded unix socket path."UNIX domain sockets must be urlencoded.".freeze
-
UNESCAPED_USER_PWD =
Error
details for an non-urlencoded user name or password."User name and password must be urlencoded.".freeze
-
UNIX_SOCKET =
Unix socket suffix.
/.sock/
-
UNSAFE =
Unsafe characters that must be urlencoded.
/[\:\/\@]/
-
URI_OPTS_DELIM =
The character delimiting options.
'?'.freeze
-
URI_OPTS_VALUE_DELIM =
The character delimiting an option and its value.
'='.freeze
Loggable
- Included
Class Method Summary
-
.get(string, opts = {}) ⇒ URI, URI::SRVProtocol
Get either a
URI
object or aSRVProtocol
URI 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
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. -
#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
URI
from 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 284
def initialize(string, = {}) 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 = 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) 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 230
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, _, _ = 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 39
attr_reader :
#servers (readonly)
The servers specified in the uri.
# File 'lib/mongo/uri.rb', line 49
attr_reader :servers
#uri_options (readonly)
Mongo::Options::Redacted of the options specified in the uri.
# File 'lib/mongo/uri.rb', line 44
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 259
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 315
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 481
def decode(value) ::URI::DEFAULT_PARSER.unescape(value) end
#encode(value) (private)
# File 'lib/mongo/uri.rb', line 485
def encode(value) CGI.escape(value).gsub('+', '%20') end
#options_mapper (private)
# File 'lib/mongo/uri.rb', line 418
def @options_mapper ||= OptionsMapper.new( logger: @options[:logger], ) end
#parse!(remaining) (private)
# File 'lib/mongo/uri.rb', line 374
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) 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( ( )) if db @database = parse_database!(db) end rescue Error::InvalidAddress => e raise_invalid_error!(e. ) end
#parse_database!(string) (private)
# File 'lib/mongo/uri.rb', line 468
def parse_database!(string) raise_invalid_error!(UNESCAPED_DATABASE) if string =~ UNSAFE decode(string) if string.length > 0 end
#parse_password!(string) (private)
# File 'lib/mongo/uri.rb', line 455
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
#parse_uri_options!(string) (private)
# File 'lib/mongo/uri.rb', line 424
def (string) = {} unless string return 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) .add_uri_option(key, value, ) end end
#parse_user!(string) (private)
# File 'lib/mongo/uri.rb', line 444
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
#raise_invalid_error!(details) (private)
# File 'lib/mongo/uri.rb', line 473
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 477
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 347
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 370
def scheme MONGODB_SCHEME end
#srv_records
# File 'lib/mongo/uri.rb', line 267
def srv_records nil end
#to_s ⇒ String
Get the uri as a string.
# File 'lib/mongo/uri.rb', line 337
def to_s reconstruct_uri end
#validate_uri_options! (private)
# File 'lib/mongo/uri.rb', line 489
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 unless [:ssl_verify_certificate].nil? unless [: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 [:ssl_cert] [:ssl_key] = [:ssl_cert] end 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 if servers.length > 1 raise_invalid_error_no_fmt!("directConnection=true cannot be used with multiple seeds") end 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] if servers.length > 1 raise_invalid_error_no_fmt!("loadBalanced=true cannot be used with multiple seeds") end 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 self.is_a?(URI::SRVProtocol) if [:srv_max_hosts] raise_invalid_error_no_fmt!("srvMaxHosts cannot be used on non-SRV URI") end if [:srv_service_name] raise_invalid_error_no_fmt!("srvServiceName cannot be used on non-SRV URI") end end if [:srv_max_hosts] && [:srv_max_hosts] > 0 if [:replica_set] raise_invalid_error_no_fmt!("srvMaxHosts > 0 cannot be used with replicaSet option") end if [:load_balanced] raise_invalid_error_no_fmt!("srvMaxHosts > 0 cannot be used with loadBalanced=true") end end end