diff --git a/lib/bson/bson.js b/lib/bson/bson.js index 5ee2b1bd..16ecc90f 100644 --- a/lib/bson/bson.js +++ b/lib/bson/bson.js @@ -128,6 +128,7 @@ BSON.prototype.serializeWithBufferAndIndex = function(object, finalBuffer, optio * @param {Object} [options.promoteValues=false] when deserializing will promote BSON values to their Node.js closest equivalent types. * @param {Object} [options.fieldsAsRaw=null] allow to specify if there what fields we wish to return as unserialized raw buffer. * @param {Object} [options.bsonRegExp=false] return BSON regular expressions as BSONRegExp instances. + * @param {boolean} [options.allowObjectSmallerThanBufferSize=false] allows the buffer to be larger than the parsed BSON object * @return {Object} returns the deserialized Javascript Object. * @api public */ @@ -183,7 +184,7 @@ BSON.prototype.deserializeStream = function( docStartIndex, options ) { - options = options != null ? options : {}; + options = Object.assign({ allowObjectSmallerThanBufferSize: true }, options); var index = startIndex; // Loop over all documents for (var i = 0; i < numberOfDocuments; i++) { @@ -191,7 +192,7 @@ BSON.prototype.deserializeStream = function( var size = data[index] | (data[index + 1] << 8) | (data[index + 2] << 16) | (data[index + 3] << 24); // Update options with index - options['index'] = index; + options.index = index; // Parse the document at this point documents[docStartIndex + i] = this.deserialize(data, options); // Adjust index by the document size diff --git a/lib/bson/parser/deserializer.js b/lib/bson/parser/deserializer.js index 4414fbe4..f3fada64 100644 --- a/lib/bson/parser/deserializer.js +++ b/lib/bson/parser/deserializer.js @@ -23,9 +23,22 @@ var deserialize = function(buffer, options, isArray) { (buffer[index + 2] << 16) | (buffer[index + 3] << 24); - // Ensure buffer is valid size - if (size < 5 || buffer.length !== size || size + index > buffer.length) { - throw new Error('corrupt bson message'); + if (size < 5) { + throw new Error(`bson size must be >= 5, is ${size}`); + } + + if (options.allowObjectSmallerThanBufferSize && buffer.length < size) { + throw new Error(`buffer length ${buffer.length} must be >= bson size ${size}`); + } + + if (!options.allowObjectSmallerThanBufferSize && buffer.length !== size) { + throw new Error(`buffer length ${buffer.length} must === bson size ${size}`); + } + + if (size + index > buffer.length) { + throw new Error( + `(bson size ${size} + options.index ${index} must be <= buffer length ${buffer.length})` + ); } // Illegal end value diff --git a/test/binary_parser.js b/test/binary_parser.js index ace884fb..15ea2b63 100644 --- a/test/binary_parser.js +++ b/test/binary_parser.js @@ -47,7 +47,11 @@ BinaryParser.decodeFloat = function decodeFloat(data, precisionBits, exponentBit } while ((precisionBits -= startBit)); return exponent === (bias << 1) + 1 - ? significand ? NaN : signal ? -Infinity : +Infinity + ? significand + ? NaN + : signal + ? -Infinity + : +Infinity : (1 + signal * -2) * (exponent || significand ? !exponent diff --git a/test/node/bson_test.js b/test/node/bson_test.js index 23e82e06..33538d27 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -2174,6 +2174,23 @@ describe('BSON', function() { // done(); // } + it('should properly deserialize multiple documents using deserializeStream', function() { + const bson = createBSON(); + const docs = [{ foo: 'bar' }, { foo: 'baz' }, { foo: 'quux' }]; + + // Serialize the test data + const serializedDocs = []; + for (let i = 0; i < docs.length; i++) { + serializedDocs[i] = bson.serialize(docs[i]); + } + const buf = Buffer.concat(serializedDocs); + + const parsedDocs = []; + bson.deserializeStream(buf, 0, docs.length, parsedDocs, 0); + + docs.forEach((doc, i) => expect(doc).to.deep.equal(parsedDocs[i])); + }); + /** * @ignore */