Skip to content

Commit 579ba5d

Browse files
authored
* Fix RUBY-1385 and RUBY-1386 * Tests * Fix tests * Fix usage
1 parent a80660a commit 579ba5d

File tree

15 files changed

+287
-26
lines changed

15 files changed

+287
-26
lines changed

lib/mongo.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@
4242
require 'mongo/uri'
4343
require 'mongo/version'
4444
require 'mongo/write_concern'
45+
require 'mongo/lint'

lib/mongo/client.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ def hash
261261
#
262262
# @since 2.0.0
263263
def initialize(addresses_or_uri, options = Options::Redacted.new)
264+
Mongo::Lint.validate_underscore_read_preference(options[:read])
264265
if addresses_or_uri.is_a?(::String)
265266
create_from_uri(addresses_or_uri, validate_options!(options))
266267
else

lib/mongo/collection/view/builder/op_query.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,15 @@ def requires_special_filter?
6868
end
6969

7070
def read_pref_formatted
71-
@read_formatted ||= ServerSelector.get(read).to_mongos if read
71+
@read_formatted ||= begin
72+
if read
73+
read_pref = ServerSelector.get(read).to_mongos
74+
Mongo::Lint.validate_camel_case_read_preference(read_pref)
75+
read_pref
76+
else
77+
nil
78+
end
79+
end
7280
end
7381

7482
def special_filter

lib/mongo/collection/view/readable.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def count(opts = {})
139139
cmd[:limit] = opts[:limit] if opts[:limit]
140140
cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
141141
cmd[:readConcern] = collection.read_concern if collection.read_concern
142+
Mongo::Lint.validate_underscore_read_preference(opts[:read])
142143
read_pref = opts[:read] || read_preference
143144
selector = ServerSelector.get(read_pref || server_selector)
144145
with_session(opts) do |session|
@@ -203,6 +204,7 @@ def estimated_document_count(opts = {})
203204
cmd = { count: collection.name }
204205
cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
205206
cmd[:readConcern] = collection.read_concern if collection.read_concern
207+
Mongo::Lint.validate_underscore_read_preference(opts[:read])
206208
read_pref = opts[:read] || read_preference
207209
selector = ServerSelector.get(read_pref || server_selector)
208210
with_session(opts) do |session|
@@ -240,6 +242,7 @@ def distinct(field_name, opts = {})
240242
:query => filter }
241243
cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
242244
cmd[:readConcern] = collection.read_concern if collection.read_concern
245+
Mongo::Lint.validate_underscore_read_preference(opts[:read])
243246
read_pref = opts[:read] || read_preference
244247
selector = ServerSelector.get(read_pref || server_selector)
245248
with_session(opts) do |session|
@@ -537,11 +540,13 @@ def collation(doc = nil)
537540
end
538541

539542
def read_preference
540-
if options[:session] && options[:session].in_transaction?
541-
options[:session].send(:txn_read_pref) || collection.client.read_preference
543+
rp = if options[:session] && options[:session].in_transaction?
544+
options[:session].txn_read_preference || collection.client.read_preference
542545
else
543546
@read_preference ||= (options[:read] || collection.read_preference)
544547
end
548+
Mongo::Lint.validate_underscore_read_preference(rp)
549+
rp
545550
end
546551

547552
def server_selector

lib/mongo/database.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ def collections
153153
#
154154
# @return [ Hash ] The result of the command execution.
155155
def command(operation, opts = {})
156-
txn_read_pref = opts[:session] && opts[:session].in_transaction? && opts[:session].txn_read_pref
156+
txn_read_pref = opts[:session] && opts[:session].in_transaction? && opts[:session].txn_read_preference
157+
Mongo::Lint.validate_underscore_read_preference(txn_read_pref)
157158
preference = ServerSelector.get(txn_read_pref || opts[:read] || ServerSelector::PRIMARY)
158159
server = preference.select_server(cluster)
159160

lib/mongo/error.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def add_label(label)
151151
require 'mongo/error/invalid_uri'
152152
require 'mongo/error/invalid_write_concern'
153153
require 'mongo/error/insufficient_iteration_count'
154+
require 'mongo/error/lint_error'
154155
require 'mongo/error/max_bson_size'
155156
require 'mongo/error/max_message_size'
156157
require 'mongo/error/mismatched_domain'

lib/mongo/error/lint_error.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright (C) 2018 MongoDB, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
module Mongo
16+
class Error
17+
18+
# Raised when the driver is used incorrectly.
19+
#
20+
# Normally the driver passes certain data to the server and lets the
21+
# server return an error if the data is invalid. This makes it possible
22+
# for the server to add functionality in the future and for older
23+
# driver versions to support such functionality transparently, but
24+
# also complicates debugging.
25+
#
26+
# Setting the environment variable MONGO_RUBY_DRIVER_LINT to 1, true
27+
# or yes will make the driver perform additional checks on data it passes
28+
# to the server, to flag failures sooner. This exception is raised on
29+
# such failures.
30+
#
31+
# @since 2.7.0
32+
class LintError < Error
33+
end
34+
end
35+
end

lib/mongo/lint.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
module Mongo
2+
# @api private
3+
module Lint
4+
def validate_underscore_read_preference(read_pref)
5+
return unless enabled?
6+
if read_pref
7+
validate_underscore_read_preference_mode(read_pref[:mode] || read_pref['mode'])
8+
end
9+
end
10+
module_function :validate_underscore_read_preference
11+
12+
def validate_underscore_read_preference_mode(mode)
13+
return unless enabled?
14+
if mode
15+
unless %w(primary primary_preferred secondary secondary_preferred nearest).include?(mode.to_s)
16+
raise Error::LintError, "Invalid read preference mode: #{mode}"
17+
end
18+
end
19+
end
20+
module_function :validate_underscore_read_preference_mode
21+
22+
def validate_camel_case_read_preference(read_pref)
23+
return unless enabled?
24+
if read_pref
25+
validate_camel_case_read_preference_mode(read_pref[:mode] || read_pref['mode'])
26+
end
27+
end
28+
module_function :validate_camel_case_read_preference
29+
30+
def validate_camel_case_read_preference_mode(mode)
31+
return unless enabled?
32+
if mode
33+
unless %w(primary primaryPreferred secondary secondaryPreferred nearest).include?(mode.to_s)
34+
raise Error::LintError, "Invalid read preference mode: #{mode}"
35+
end
36+
end
37+
end
38+
module_function :validate_camel_case_read_preference_mode
39+
40+
def enabled?
41+
ENV['MONGO_RUBY_DRIVER_LINT'] && %w(1 yes true).include?(ENV['MONGO_RUBY_DRIVER_LINT'].downcase)
42+
end
43+
module_function :enabled?
44+
end
45+
end

lib/mongo/operation/shared/read_preference_supported.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ def options(server)
3030

3131
def update_selector_for_read_pref(sel, server)
3232
if read && server.mongos? && read_pref = read.to_mongos
33+
Mongo::Lint.validate_camel_case_read_preference(read_pref)
3334
sel = sel[:$query] ? sel : {:$query => sel}
34-
sel.merge(:$readPreference => read_pref)
35+
sel = sel.merge(:$readPreference => read_pref)
3536
else
3637
sel
3738
end

lib/mongo/operation/shared/sessions_supported.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ def suppress_read_write_concern!(selector)
9999
session.suppress_read_write_concern!(selector)
100100
end
101101

102-
def validate_read_pref!(selector)
103-
session.validate_read_pref!(selector) if read_command?(selector)
102+
def validate_read_preference!(selector)
103+
session.validate_read_preference!(selector) if read_command?(selector)
104104
end
105105

106106
def update_session_state!
@@ -123,7 +123,7 @@ def command(server)
123123
apply_autocommit!(sel)
124124
apply_txn_opts!(sel)
125125
suppress_read_write_concern!(sel)
126-
validate_read_pref!(sel)
126+
validate_read_preference!(sel)
127127
update_session_state!
128128
apply_txn_num!(sel)
129129
end
@@ -136,7 +136,7 @@ def command(server)
136136
apply_autocommit!(sel)
137137
apply_txn_opts!(sel)
138138
suppress_read_write_concern!(sel)
139-
validate_read_pref!(sel)
139+
validate_read_preference!(sel)
140140
update_session_state!
141141
apply_txn_num!(sel)
142142
end

0 commit comments

Comments
 (0)