Skip to content

Commit 2330ab1

Browse files
authored
fix(NODE-3451): fix performance regression from v1 (#451)
1 parent cb82a80 commit 2330ab1

File tree

2 files changed

+19
-14
lines changed

2 files changed

+19
-14
lines changed

src/bson.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ export function deserialize(
216216
buffer: Buffer | ArrayBufferView | ArrayBuffer,
217217
options: DeserializeOptions = {}
218218
): Document {
219-
return internalDeserialize(ensureBuffer(buffer), options);
219+
return internalDeserialize(buffer instanceof Buffer ? buffer : ensureBuffer(buffer), options);
220220
}
221221

222222
/** @public */

src/parser/deserializer.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ export function deserialize(
9393
return deserializeObject(buffer, index, options, isArray);
9494
}
9595

96+
const allowedDBRefKeys = /^\$ref$|^\$id$|^\$db$/;
97+
9698
function deserializeObject(
9799
buffer: Buffer,
98100
index: number,
@@ -134,6 +136,8 @@ function deserializeObject(
134136
let arrayIndex = 0;
135137
const done = false;
136138

139+
let isPossibleDBRef = isArray ? false : null;
140+
137141
// While we have more left data left keep parsing
138142
while (!done) {
139143
// Read the type
@@ -152,6 +156,9 @@ function deserializeObject(
152156
// If are at the end of the buffer there is a problem with the document
153157
if (i >= buffer.byteLength) throw new Error('Bad BSON Document: illegal CString');
154158
const name = isArray ? arrayIndex++ : buffer.toString('utf8', index, i);
159+
if (isPossibleDBRef !== false && (name as string)[0] === '$') {
160+
isPossibleDBRef = allowedDBRefKeys.test(name as string);
161+
}
155162
let value;
156163

157164
index = i + 1;
@@ -169,12 +176,17 @@ function deserializeObject(
169176
)
170177
throw new Error('bad string length in bson');
171178

172-
if (!validateUtf8(buffer, index, index + stringSize - 1)) {
173-
throw new Error('Invalid UTF-8 string in BSON document');
174-
}
175-
176179
value = buffer.toString('utf8', index, index + stringSize - 1);
177180

181+
for (let i = 0; i < value.length; i++) {
182+
if (value.charCodeAt(i) === 0xfffd) {
183+
if (!validateUtf8(buffer, index, index + stringSize - 1)) {
184+
throw new Error('Invalid UTF-8 string in BSON document');
185+
}
186+
break;
187+
}
188+
}
189+
178190
index = index + stringSize;
179191
} else if (elementType === constants.BSON_DATA_OID) {
180192
const oid = Buffer.alloc(12);
@@ -625,15 +637,8 @@ function deserializeObject(
625637
throw new Error('corrupt object bson');
626638
}
627639

628-
// check if object's $ keys are those of a DBRef
629-
const dollarKeys = Object.keys(object).filter(k => k.startsWith('$'));
630-
let valid = true;
631-
dollarKeys.forEach(k => {
632-
if (['$ref', '$id', '$db'].indexOf(k) === -1) valid = false;
633-
});
634-
635-
// if a $key not in "$ref", "$id", "$db", don't make a DBRef
636-
if (!valid) return object;
640+
// if we did not find "$ref", "$id", "$db", or found an extraneous $key, don't make a DBRef
641+
if (!isPossibleDBRef) return object;
637642

638643
if (isDBRefLike(object)) {
639644
const copy = Object.assign({}, object) as Partial<DBRefLike>;

0 commit comments

Comments
 (0)