mongo 2.13.0.rc1 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db8c88ed58f349728a9361db891376926e93450f4a8ac86aae0bc67599c91a7b
4
- data.tar.gz: b4f7daaf1d43b55839c1f689504d4f1c212c638e45f6d2211732bc07a41f77e5
3
+ metadata.gz: df3eb3a5733323f2f4440c67bc0173661ada194ecb35374e8e78345e2d072525
4
+ data.tar.gz: 63227bff6f14e3100f86a747b3e5d577812dd74d6da8061a069d8a313ecce09c
5
5
  SHA512:
6
- metadata.gz: 22471d116179fff42716707a40fa18ebc3c53492a6313bb16be96f447db725110b8ed0b3ee8e199026098a59b8f2941290cd1493249c8e9120ec2849e0229fa1
7
- data.tar.gz: 8965e04c6926343e4363110d010e14b1a8fde146eb4e239f620005f251ff24b63393bc13f5f332ac4d8aa39cc790a66f080401d9b0923c54a8b40b7d80aa25ea
6
+ metadata.gz: '02253019a9aab19c94dbb2a4e459a84c1fa6f1383eca9d5b1daa26bf1c2aa1a96c32f52a23267b0b7b5c58fc469144d0c1722b4f79593ae7563ac0c9deb55d95'
7
+ data.tar.gz: e02d93a95630d770f20a37cbe91a4dc18c98cb18e684da4b2a538a70afaaf61731e808832b2fe9aadca484dacfc8dce43cedf356ef00db019a03d77e9283cc45
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -61,9 +61,13 @@ module Mongo
61
61
  %i(access_key_id secret_access_key host server_nonce).each do |arg|
62
62
  value = instance_variable_get("@#{arg}")
63
63
  if value.nil? || value.empty?
64
- raise ArgumentError, "Value for #{arg} is required"
64
+ raise Error::InvalidServerAuthResponse, "Value for '#{arg}' is required"
65
65
  end
66
66
  end
67
+
68
+ if host && host.length > 255
69
+ raise Error::InvalidServerAuthHost, "Value for 'host' is too long: #{@host}"
70
+ end
67
71
  end
68
72
 
69
73
  # @return [ String ] access_key_id The access key id.
@@ -98,8 +102,28 @@ module Mongo
98
102
 
99
103
  # @return [ String ] region The region of the host, derived from the host.
100
104
  def region
101
- # TODO implement region derivation when SPEC-1646 is done.
102
- 'us-east-1'
105
+ # Common case
106
+ if host == 'sts.amazonaws.com'
107
+ return 'us-east-1'
108
+ end
109
+
110
+ if host.start_with?('.')
111
+ raise Error::InvalidServerAuthHost, "Host begins with a period: #{host}"
112
+ end
113
+ if host.end_with?('.')
114
+ raise Error::InvalidServerAuthHost, "Host ends with a period: #{host}"
115
+ end
116
+
117
+ parts = host.split('.')
118
+ if parts.any? { |part| part.empty? }
119
+ raise Error::InvalidServerAuthHost, "Host has an empty component: #{host}"
120
+ end
121
+
122
+ if parts.length == 1
123
+ 'us-east-1'
124
+ else
125
+ parts[1]
126
+ end
103
127
  end
104
128
 
105
129
  # Returns the scope of the request, per the AWS signature V4 specification.
@@ -104,6 +104,7 @@ module Mongo
104
104
  :truncate_logs,
105
105
  :user,
106
106
  :wait_queue_timeout,
107
+ :wrapping_libraries,
107
108
  :write,
108
109
  :write_concern,
109
110
  :zlib_compression_level,
@@ -375,6 +376,10 @@ module Mongo
375
376
  # @option options [ String ] :user The user name.
376
377
  # @option options [ Float ] :wait_queue_timeout The time to wait, in
377
378
  # seconds, in the connection pool for a connection to be checked in.
379
+ # @option options [ Array<Hash> ] :wrapping_libraries Information about
380
+ # libraries such as ODMs that are wrapping the driver, to be added to
381
+ # metadata sent to the server. Specify the lower level libraries first.
382
+ # Allowed hash keys: :name, :version, :platform.
378
383
  # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
379
384
  # option.
380
385
  # @option options [ Hash ] :write_concern The write concern options.
@@ -1160,6 +1165,36 @@ module Mongo
1160
1165
  raise ArgumentError, ":bg_error_backtrace option value must be true, false, nil or a positive integer: #{value}"
1161
1166
  end
1162
1167
  end
1168
+
1169
+ if libraries = options[:wrapping_libraries]
1170
+ unless Array === libraries
1171
+ raise ArgumentError, ":wrapping_libraries must be an array of hashes: #{libraries}"
1172
+ end
1173
+
1174
+ libraries = libraries.map do |library|
1175
+ Utils.shallow_symbolize_keys(library)
1176
+ end
1177
+
1178
+ libraries.each do |library|
1179
+ unless Hash === library
1180
+ raise ArgumentError, ":wrapping_libraries element is not a hash: #{library}"
1181
+ end
1182
+
1183
+ if library.empty?
1184
+ raise ArgumentError, ":wrapping_libraries element is empty"
1185
+ end
1186
+
1187
+ unless (library.keys - %i(name platform version)).empty?
1188
+ raise ArgumentError, ":wrapping_libraries element has invalid keys (allowed keys: :name, :platform, :version): #{library}"
1189
+ end
1190
+
1191
+ library.each do |key, value|
1192
+ if value.include?('|')
1193
+ raise ArgumentError, ":wrapping_libraries element value cannot include '|': #{value}"
1194
+ end
1195
+ end
1196
+ end
1197
+ end
1163
1198
  end
1164
1199
 
1165
1200
  # Validates all authentication-related options after they are set on the client
@@ -190,6 +190,8 @@ require 'mongo/error/invalid_application_name'
190
190
  require 'mongo/error/invalid_nonce'
191
191
  require 'mongo/error/invalid_replacement_document'
192
192
  require 'mongo/error/invalid_server_auth_response'
193
+ # Subclass of InvalidServerAuthResponse
194
+ require 'mongo/error/invalid_server_auth_host'
193
195
  require 'mongo/error/invalid_server_preference'
194
196
  require 'mongo/error/invalid_session'
195
197
  require 'mongo/error/invalid_signature'
@@ -0,0 +1,22 @@
1
+ # Copyright (C) 2020 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 server returned an invalid Host value in AWS auth.
19
+ class InvalidServerAuthHost < InvalidServerAuthResponse
20
+ end
21
+ end
22
+ end
@@ -120,6 +120,9 @@ module Mongo
120
120
  # a geo index.
121
121
  # @option options [ Hash ] :partial_filter_expression Specify a filter for a partial
122
122
  # index.
123
+ # @option options [ Boolean ] :hidden When :hidden is true, this index will
124
+ # exist on the collection but not be used by the query planner when
125
+ # executing operations.
123
126
  # @option options [ String | Integer ] :commit_quorum Specify how many
124
127
  # data-bearing members of a replica set, including the primary, must
125
128
  # complete the index builds successfully before the primary marks
@@ -147,6 +147,8 @@ module Mongo
147
147
  #
148
148
  # @since 2.5.0
149
149
  def serialize(buffer = BSON::ByteBuffer.new, max_bson_size = nil)
150
+ validate_document_size!(max_bson_size)
151
+
150
152
  super
151
153
  add_check_sum(buffer)
152
154
  buffer
@@ -275,6 +277,23 @@ module Mongo
275
277
 
276
278
  private
277
279
 
280
+ # Validate that the documents in this message are all smaller than the
281
+ # maxBsonObjectSize. If not, raise an exception.
282
+ def validate_document_size!(max_bson_size)
283
+ max_bson_size ||= Mongo::Server::ConnectionBase::DEFAULT_MAX_BSON_OBJECT_SIZE
284
+
285
+ contains_too_large_document = @sections.any? do |section|
286
+ section[:type] == 1 &&
287
+ section[:payload][:sequence].any? do |document|
288
+ document.to_bson.length > max_bson_size
289
+ end
290
+ end
291
+
292
+ if contains_too_large_document
293
+ raise Error::MaxBSONSize.new('The document exceeds maximum allowed BSON object size after serialization')
294
+ end
295
+ end
296
+
278
297
  def command
279
298
  @command ||= if @main_document
280
299
  @main_document.dup.tap do |cmd|
@@ -65,12 +65,17 @@ module Mongo
65
65
  # the metadata printed to the mongod logs upon establishing a connection
66
66
  # in server versions >= 3.4.
67
67
  # @option options [ String ] :user The user name.
68
+ # @option options [ Array<Hash> ] :wrapping_libraries Information about
69
+ # libraries such as ODMs that are wrapping the driver. Specify the
70
+ # lower level libraries first. Allowed hash keys: :name, :version,
71
+ # :platform.
68
72
  #
69
73
  # @since 2.4.0
70
74
  def initialize(options)
71
75
  @app_name = options[:app_name].to_s if options[:app_name]
72
76
  @platform = options[:platform]
73
77
  @compressors = options[:compressors] || []
78
+ @wrapping_libraries = options[:wrapping_libraries]
74
79
 
75
80
  if options[:user] && !options[:auth_mech]
76
81
  auth_db = options[:auth_source] || 'admin'
@@ -78,6 +83,10 @@ module Mongo
78
83
  end
79
84
  end
80
85
 
86
+ # @return [ Array<Hash> | nil ] Information about libraries wrapping
87
+ # the driver.
88
+ attr_reader :wrapping_libraries
89
+
81
90
  # Get the bytes of the ismaster message including this metadata.
82
91
  #
83
92
  # @api private
@@ -140,9 +149,17 @@ module Mongo
140
149
  end
141
150
 
142
151
  def driver_doc
152
+ names = [DRIVER_NAME]
153
+ versions = [Mongo::VERSION]
154
+ if wrapping_libraries
155
+ wrapping_libraries.each do |library|
156
+ names << library[:name] || ''
157
+ versions << library[:version] || ''
158
+ end
159
+ end
143
160
  {
144
- name: DRIVER_NAME,
145
- version: Mongo::VERSION
161
+ name: names.join('|'),
162
+ version: versions.join('|'),
146
163
  }
147
164
  end
148
165
 
@@ -175,12 +192,19 @@ module Mongo
175
192
  ruby_versions = ["Ruby #{RUBY_VERSION}"]
176
193
  platforms = [RUBY_PLATFORM]
177
194
  end
178
- [
195
+ platform = [
179
196
  @platform,
180
197
  *ruby_versions,
181
198
  *platforms,
182
199
  RbConfig::CONFIG['build'],
183
200
  ].compact.join(', ')
201
+ platforms = [platform]
202
+ if wrapping_libraries
203
+ wrapping_libraries.each do |library|
204
+ platforms << library[:platform] || ''
205
+ end
206
+ end
207
+ platforms.join('|')
184
208
  end
185
209
  end
186
210
  end
@@ -186,9 +186,6 @@ module Mongo
186
186
  end
187
187
 
188
188
  def serialize(message, client, buffer = BSON::ByteBuffer.new)
189
- start_size = 0
190
- final_message = message.maybe_compress(compressor, options[:zlib_compression_level])
191
-
192
189
  # Driver specifications only mandate the fixed 16MiB limit for
193
190
  # serialized BSON documents. However, the server returns its
194
191
  # active serialized BSON document size limit in the ismaster response,
@@ -213,12 +210,41 @@ module Mongo
213
210
  max_bson_size += MAX_BSON_COMMAND_OVERHEAD
214
211
  end
215
212
 
216
- final_message.serialize(buffer, max_bson_size)
217
- if max_message_size &&
218
- (buffer.length - start_size) > max_message_size
219
- then
220
- raise Error::MaxMessageSize.new(max_message_size)
213
+ # RUBY-2234: It is necessary to check that the message size does not
214
+ # exceed the maximum bson object size before compressing and serializing
215
+ # the final message.
216
+ #
217
+ # This is to avoid the case where the user performs a bulk write
218
+ # larger than 16MiB which, when compressed, becomes smaller than 16MiB.
219
+ # If the driver does not split the bulk writes prior to compression,
220
+ # the entire operation will be sent to the server, which will raise an
221
+ # error because the uncompressed operation exceeds the maximum bson size.
222
+ #
223
+ # To address this problem, we serialize the message prior to compression
224
+ # and raise an exception if the serialized message exceeds the maximum
225
+ # bson size.
226
+ if max_message_size
227
+ # Create a separate buffer that contains the un-compressed message
228
+ # for the purpose of checking its size. Write any pre-existing contents
229
+ # from the original buffer into the temporary one.
230
+ temp_buffer = BSON::ByteBuffer.new
231
+
232
+ # TODO: address the fact that this line mutates the buffer.
233
+ temp_buffer.put_bytes(buffer.get_bytes(buffer.length))
234
+
235
+ message.serialize(temp_buffer, max_bson_size)
236
+ if temp_buffer.length > max_message_size
237
+ raise Error::MaxMessageSize.new(max_message_size)
238
+ end
221
239
  end
240
+
241
+ # RUBY-2335: When the un-compressed message is smaller than the maximum
242
+ # bson size limit, the message will be serialized twice. The operations
243
+ # layer should be refactored to allow compression on an already-
244
+ # serialized message.
245
+ final_message = message.maybe_compress(compressor, options[:zlib_compression_level])
246
+ final_message.serialize(buffer, max_bson_size)
247
+
222
248
  buffer
223
249
  end
224
250
  end
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.13.0.rc1'.freeze
20
+ VERSION = '2.13.0'.freeze
21
21
  end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Bulk writes' do
4
+ before do
5
+ authorized_collection.drop
6
+ end
7
+
8
+ context 'when bulk write is larger than 48MB' do
9
+ let(:operations) do
10
+ [ { insert_one: { text: 'a' * 1000 * 1000 } } ] * 48
11
+ end
12
+
13
+ it 'succeeds' do
14
+ expect do
15
+ authorized_collection.bulk_write(operations)
16
+ end.not_to raise_error
17
+ end
18
+ end
19
+ end
@@ -113,7 +113,7 @@ describe 'Bulk writes with auto-encryption enabled' do
113
113
  it 'raises an exception' do
114
114
  expect do
115
115
  bulk_write.execute
116
- end.to raise_error(Mongo::Error::MaxBSONSize, /maximum allowed size: 16777216 bytes/)
116
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
117
117
  end
118
118
  end
119
119
  end
@@ -255,7 +255,7 @@ describe 'Bulk writes with auto-encryption enabled' do
255
255
  it 'raises an exception' do
256
256
  expect do
257
257
  bulk_write.execute
258
- end.to raise_error(Mongo::Error::MaxBSONSize, /maximum allowed size: 16777216 bytes/)
258
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
259
259
  end
260
260
  end
261
261
  end
@@ -346,7 +346,7 @@ describe 'Bulk writes with auto-encryption enabled' do
346
346
  it 'raises an exception' do
347
347
  expect do
348
348
  perform_bulk_write
349
- end.to raise_error(Mongo::Error::MaxBSONSize, /maximum allowed size: 16777216 bytes/)
349
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
350
350
  end
351
351
  end
352
352
  end
@@ -62,13 +62,30 @@ describe 'BSON & command size limits' do
62
62
  authorized_collection.insert_one(document)
63
63
  end
64
64
 
65
- it 'fails on the server when a document larger than 16MiB is inserted' do
66
- document = { key: 'a' * (max_document_size - 27), _id: 'foo' }
67
- expect(document.to_bson.length).to eq(max_document_size+1)
65
+ context 'on server versions >= 3.6' do
66
+ min_server_fcv '3.6'
68
67
 
69
- lambda do
70
- authorized_collection.insert_one(document)
71
- end.should raise_error(Mongo::Error::OperationFailure, /object to insert too large/)
68
+ it 'fails on the driver when a document larger than 16MiB is inserted' do
69
+ document = { key: 'a' * (max_document_size - 27), _id: 'foo' }
70
+ expect(document.to_bson.length).to eq(max_document_size+1)
71
+
72
+ lambda do
73
+ authorized_collection.insert_one(document)
74
+ end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
75
+ end
76
+ end
77
+
78
+ context 'on server versions <= 3.4' do
79
+ max_server_fcv '3.4'
80
+
81
+ it 'fails on the server when a document larger than 16MiB is inserted' do
82
+ document = { key: 'a' * (max_document_size - 27), _id: 'foo' }
83
+ expect(document.to_bson.length).to eq(max_document_size+1)
84
+
85
+ lambda do
86
+ authorized_collection.insert_one(document)
87
+ end.should raise_error(Mongo::Error::OperationFailure, /object to insert too large/)
88
+ end
72
89
  end
73
90
 
74
91
  it 'fails in the driver when a document larger than 16MiB+16KiB is inserted' do
@@ -81,10 +98,6 @@ describe 'BSON & command size limits' do
81
98
  end
82
99
 
83
100
  it 'allows bulk writes of multiple documents of exactly 16 MiB each' do
84
- if SpecConfig.instance.compressors
85
- pending "RUBY-2234"
86
- end
87
-
88
101
  documents = []
89
102
  1.upto(3) do |index|
90
103
  document = { key: 'a' * (max_document_size - 28), _id: "in#{index}" }
@@ -0,0 +1,42 @@
1
+ require 'lite_spec_helper'
2
+
3
+ AWS_REGION_TEST_CASES = {
4
+ 'sts.amazonaws.com' => 'us-east-1',
5
+ 'sts.us-west-2.amazonaws.com' => 'us-west-2',
6
+ 'sts.us-west-2.amazonaws.com.ch' => 'us-west-2',
7
+ 'example.com' => 'com',
8
+ 'localhost' => 'us-east-1',
9
+ 'sts..com' => Mongo::Error::InvalidServerAuthHost,
10
+ '.amazonaws.com' => Mongo::Error::InvalidServerAuthHost,
11
+ 'sts.amazonaws.' => Mongo::Error::InvalidServerAuthHost,
12
+ '' => Mongo::Error::InvalidServerAuthResponse,
13
+ 'x' * 256 => Mongo::Error::InvalidServerAuthHost,
14
+ }
15
+
16
+ describe 'AWS auth region tests' do
17
+
18
+ AWS_REGION_TEST_CASES.each do |host, expected_region|
19
+ context "host '#{host}'" do
20
+ let(:request) do
21
+ Mongo::Auth::Aws::Request.new(access_key_id: 'access_key_id',
22
+ secret_access_key: 'secret_access_key',
23
+ session_token: 'session_token',
24
+ host: host,
25
+ server_nonce: 'server_nonce',
26
+ )
27
+ end
28
+
29
+ if expected_region.is_a?(String)
30
+ it 'derives expected region' do
31
+ request.region.should == expected_region
32
+ end
33
+ else
34
+ it 'fails with an error' do
35
+ lambda do
36
+ request.region
37
+ end.should raise_error(expected_region)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end