Skip to content

Commit 5e9bbc2

Browse files
asdf
1 parent 65e0e15 commit 5e9bbc2

File tree

10 files changed

+106
-210
lines changed

10 files changed

+106
-210
lines changed

src/bson.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,14 @@ export function resolveBSONOptions(
132132
options?.enableUtf8Validation ?? parentOptions?.enableUtf8Validation ?? true
133133
};
134134
}
135+
136+
/** @internal */
137+
export function parseUtf8ValidationOption(options?: { enableUtf8Validation?: boolean }): {
138+
utf8: { writeErrors: false } | false;
139+
} {
140+
const enableUtf8Validation = options?.enableUtf8Validation;
141+
if (enableUtf8Validation === false) {
142+
return { utf8: false };
143+
}
144+
return { utf8: { writeErrors: false } };
145+
}

src/cmap/connection.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { type DeserializeOptions } from 'bson';
12
import { type Readable, Transform, type TransformCallback } from 'stream';
23
import { clearTimeout, setTimeout } from 'timers';
34

@@ -487,7 +488,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
487488

488489
// If `documentsReturnedIn` not set or raw is not enabled, use input bson options
489490
// Otherwise, support raw flag. Raw only works for cursors that hardcode firstBatch/nextBatch fields
490-
const bsonOptions =
491+
const bsonOptions: DeserializeOptions =
491492
options.documentsReturnedIn == null || !options.raw
492493
? options
493494
: {

src/cmap/wire_protocol/on_demand/document.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1+
import { type DeserializeOptions } from 'bson';
2+
13
import {
24
Binary,
35
type BSONElement,
46
BSONError,
5-
type BSONSerializeOptions,
67
BSONType,
78
deserialize,
89
getBigInt64LE,
910
getFloat64LE,
1011
getInt32LE,
1112
ObjectId,
1213
parseToElementsToArray,
13-
pluckBSONSerializeOptions,
1414
Timestamp,
1515
toUTF8
1616
} from '../../../bson';
@@ -44,6 +44,15 @@ export type JSTypeOf = {
4444
/** @internal */
4545
type CachedBSONElement = { element: BSONElement; value: any | undefined };
4646

47+
/**
48+
* @internal
49+
*
50+
* Options for `OnDemandDocument.toObject()`. Validation is required to ensure
51+
* that callers provide utf8 validation options. */
52+
export type OnDemandDocumentDeserializeOptions = DeserializeOptions & {
53+
validation: NonNullable<DeserializeOptions['validation']>;
54+
};
55+
4756
/** @internal */
4857
export class OnDemandDocument {
4958
/**
@@ -330,14 +339,12 @@ export class OnDemandDocument {
330339
* Deserialize this object, DOES NOT cache result so avoid multiple invocations
331340
* @param options - BSON deserialization options
332341
*/
333-
public toObject(options?: BSONSerializeOptions): Record<string, any> {
334-
const exactBSONOptions = {
335-
...pluckBSONSerializeOptions(options ?? {}),
336-
validation: this.parseBsonSerializationOptions(options),
342+
public toObject(options?: OnDemandDocumentDeserializeOptions): Record<string, any> {
343+
return deserialize(this.bson, {
344+
...options,
337345
index: this.offset,
338346
allowObjectSmallerThanBufferSize: true
339-
};
340-
return deserialize(this.bson, exactBSONOptions);
347+
});
341348
}
342349

343350
private parseBsonSerializationOptions(options?: { enableUtf8Validation?: boolean }): {

src/cmap/wire_protocol/responses.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1+
import { type DeserializeOptions } from 'bson';
2+
13
import {
24
type BSONElement,
35
type BSONSerializeOptions,
46
BSONType,
57
type Document,
68
Long,
79
parseToElementsToArray,
10+
parseUtf8ValidationOption,
11+
pluckBSONSerializeOptions,
812
type Timestamp
913
} from '../../bson';
1014
import { MongoUnexpectedServerResponseError } from '../../error';
1115
import { type ClusterTime } from '../../sdam/common';
1216
import { decorateDecryptionResult, ns } from '../../utils';
13-
import { type JSTypeOf, OnDemandDocument } from './on_demand/document';
17+
import {
18+
type JSTypeOf,
19+
OnDemandDocument,
20+
type OnDemandDocumentDeserializeOptions
21+
} from './on_demand/document';
1422

1523
// eslint-disable-next-line no-restricted-syntax
1624
const enum BSONElementOffset {
@@ -112,7 +120,8 @@ export class MongoDBResponse extends OnDemandDocument {
112120
this.get('recoveryToken', BSONType.object)?.toObject({
113121
promoteValues: false,
114122
promoteLongs: false,
115-
promoteBuffers: false
123+
promoteBuffers: false,
124+
validation: { utf8: true }
116125
}) ?? null
117126
);
118127
}
@@ -165,6 +174,14 @@ export class MongoDBResponse extends OnDemandDocument {
165174
}
166175
return this.clusterTime ?? null;
167176
}
177+
178+
public override toObject(options?: BSONSerializeOptions): Record<string, any> {
179+
const exactBSONOptions = {
180+
...pluckBSONSerializeOptions(options ?? {}),
181+
validation: parseUtf8ValidationOption(options)
182+
};
183+
return super.toObject(exactBSONOptions);
184+
}
168185
}
169186

170187
/** @internal */
@@ -248,12 +265,13 @@ export class CursorResponse extends MongoDBResponse {
248265
this.cursor.get('postBatchResumeToken', BSONType.object)?.toObject({
249266
promoteValues: false,
250267
promoteLongs: false,
251-
promoteBuffers: false
268+
promoteBuffers: false,
269+
validation: { utf8: true }
252270
}) ?? null
253271
);
254272
}
255273

256-
public shift(options?: BSONSerializeOptions): any {
274+
public shift(options: OnDemandDocumentDeserializeOptions): any {
257275
if (this.iterated >= this.batchSize) {
258276
return null;
259277
}
@@ -305,7 +323,7 @@ export class ExplainedCursorResponse extends CursorResponse {
305323
return this._length;
306324
}
307325

308-
override shift(options?: BSONSerializeOptions | undefined) {
326+
override shift(options?: DeserializeOptions) {
309327
if (this._length === 0) return null;
310328
this._length -= 1;
311329
return this.toObject(options);

src/cursor/abstract_cursor.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
import { type DeserializeOptions } from 'bson';
12
import { Readable, Transform } from 'stream';
23

3-
import { type BSONSerializeOptions, type Document, Long, pluckBSONSerializeOptions } from '../bson';
4+
import {
5+
type BSONSerializeOptions,
6+
type Document,
7+
Long,
8+
parseUtf8ValidationOption,
9+
pluckBSONSerializeOptions
10+
} from '../bson';
11+
import { type OnDemandDocumentDeserializeOptions } from '../cmap/wire_protocol/on_demand/document';
412
import { type CursorResponse } from '../cmap/wire_protocol/responses';
513
import {
614
MongoAPIError,
@@ -157,6 +165,9 @@ export abstract class AbstractCursor<
157165
/** @event */
158166
static readonly CLOSE = 'close' as const;
159167

168+
/** @internal */
169+
protected deserializationOptions: OnDemandDocumentDeserializeOptions;
170+
160171
/** @internal */
161172
protected constructor(
162173
client: MongoClient,
@@ -211,6 +222,13 @@ export abstract class AbstractCursor<
211222
} else {
212223
this.cursorSession = this.cursorClient.startSession({ owner: this, explicit: false });
213224
}
225+
226+
this.deserializationOptions = {
227+
...this.cursorOptions,
228+
validation: {
229+
utf8: options?.enableUtf8Validation === false ? false : true
230+
}
231+
};
214232
}
215233

216234
/**
@@ -304,7 +322,7 @@ export abstract class AbstractCursor<
304322
);
305323

306324
for (let count = 0; count < documentsToRead; count++) {
307-
const document = this.documents?.shift(this.cursorOptions);
325+
const document = this.documents?.shift(this.deserializationOptions);
308326
if (document != null) {
309327
bufferedDocs.push(document);
310328
}
@@ -406,7 +424,7 @@ export abstract class AbstractCursor<
406424
}
407425

408426
do {
409-
const doc = this.documents?.shift(this.cursorOptions);
427+
const doc = this.documents?.shift(this.deserializationOptions);
410428
if (doc != null) {
411429
if (this.transform != null) return await this.transformDocument(doc);
412430
return doc;
@@ -425,15 +443,15 @@ export abstract class AbstractCursor<
425443
throw new MongoCursorExhaustedError();
426444
}
427445

428-
let doc = this.documents?.shift(this.cursorOptions);
446+
let doc = this.documents?.shift(this.deserializationOptions);
429447
if (doc != null) {
430448
if (this.transform != null) return await this.transformDocument(doc);
431449
return doc;
432450
}
433451

434452
await this.fetchBatch();
435453

436-
doc = this.documents?.shift(this.cursorOptions);
454+
doc = this.documents?.shift(this.deserializationOptions);
437455
if (doc != null) {
438456
if (this.transform != null) return await this.transformDocument(doc);
439457
return doc;

src/cursor/aggregation_cursor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class AggregationCursor<TSchema = any> extends AbstractCursor<TSchema> {
7676
explain: verbosity ?? true
7777
})
7878
)
79-
).shift(this.aggregateOptions);
79+
).shift(this.deserializationOptions);
8080
}
8181

8282
/** Add a stage to the aggregation pipeline

src/cursor/find_cursor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
143143
explain: verbosity ?? true
144144
})
145145
)
146-
).shift(this.findOptions);
146+
).shift(this.deserializationOptions);
147147
}
148148

149149
/** Set the cursor query */

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,11 @@ export type { ClientMetadata, ClientMetadataOptions } from './cmap/handshake/cli
302302
export type { ConnectionPoolMetrics } from './cmap/metrics';
303303
export type { StreamDescription, StreamDescriptionOptions } from './cmap/stream_description';
304304
export type { CompressorName } from './cmap/wire_protocol/compression';
305-
export type { JSTypeOf, OnDemandDocument } from './cmap/wire_protocol/on_demand/document';
305+
export type {
306+
JSTypeOf,
307+
OnDemandDocument,
308+
OnDemandDocumentDeserializeOptions
309+
} from './cmap/wire_protocol/on_demand/document';
306310
export type {
307311
CursorResponse,
308312
MongoDBResponse,

0 commit comments

Comments
 (0)