mongo 2.13.0.rc1 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
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