lib/mongo/uri.rb in mongo-2.12.4 vs lib/mongo/uri.rb in mongo-2.13.0.beta1
- old
+ new
@@ -1,6 +1,6 @@
-# Copyright (C) 2014-2019 MongoDB, Inc.
+# Copyright (C) 2014-2020 MongoDB Inc.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
@@ -190,16 +190,17 @@
# Map of URI authentication mechanisms to Ruby driver mechanisms
#
# @since 2.0.0
AUTH_MECH_MAP = {
'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
+ 'SCRAM-SHA-256' => :scram256,
}.freeze
# Options that are allowed to appear more than once in the uri.
#
# In order to follow the URI options spec requirement that all instances
@@ -293,46 +294,11 @@
end
if remaining.empty?
raise_invalid_error!('No hosts in the URI')
end
parse!(remaining)
-
- # 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
- 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
+ validate_uri_options!
end
# Get the credentials provided in the URI.
#
# @example Get the credentials.
@@ -433,13 +399,10 @@
end
key, value = option_str.split('=', 2)
if value.nil?
raise_invalid_error!("Option #{key} has no value")
end
- if value.index('=')
- raise_invalid_error!("Value for option #{key} contains the key/value delimiter (=): #{value}")
- end
key = decode(key)
value = decode(value)
add_uri_option(key, value, uri_options)
end
uri_options
@@ -485,11 +448,11 @@
def decode(value)
::URI::DEFAULT_PARSER.unescape(value)
end
def encode(value)
- ::URI.encode(value)
+ CGI.escape(value).gsub('+', '%20')
end
# Hash for storing map of URI option parameters to conversion strategies
URI_OPTION_MAP = {}
@@ -542,10 +505,11 @@
uri_option 'tlscertificatekeyfile', :ssl_cert
uri_option 'tlscertificatekeyfilepassword', :ssl_key_pass_phrase
uri_option 'tlsinsecure', :ssl_verify, :type => :inverse_bool
# Topology options
+ uri_option 'directconnection', :direct_connection, type: :bool
uri_option 'connect', :connect, type: :symbol
# Auth Options
uri_option 'authsource', :auth_source
uri_option 'authmechanism', :auth_mech, :type => :auth_mech
@@ -678,11 +642,11 @@
# @param value [ String ] The auth mechanism properties string.
#
# @return [ Hash ] The auth mechanism properties hash.
def auth_mech_props(value)
properties = hash_extractor('authMechanismProperties', value)
- if properties[:canonicalize_host_name]
+ if properties && properties[:canonicalize_host_name]
properties.merge!(canonicalize_host_name:
properties[:canonicalize_host_name].downcase == 'true')
end
properties
end
@@ -853,27 +817,77 @@
#
# @param value [ String ] The string to build a hash from.
#
# @return [ Hash ] The hash built from the string.
def hash_extractor(name, value)
- value.split(',').reduce({}) do |set, tag|
+ h = {}
+ value.split(',').each do |tag|
k, v = tag.split(':')
if v.nil?
- log_warn("Invalid hash value for #{name}: #{value}")
- return nil
+ log_warn("Invalid hash value for #{name}: key `#{k}` does not have a value: #{value}")
end
- set.merge(k.downcase.to_sym => v)
+ h[k.downcase.to_sym] = v
end
+ h
end
# Extract values from the string and put them into an array.
#
# @param [ String ] value The string to build an array from.
#
# @return [ Array ] The array built from the string.
def array(value)
value.split(',')
+ end
+
+ 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
+ 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
end
end
require 'mongo/uri/srv_protocol'