Skip to content

Commit a675fab

Browse files
add metadata truncation
1 parent aa8fb71 commit a675fab

File tree

12 files changed

+227
-54
lines changed

12 files changed

+227
-54
lines changed

src/cmap/connect.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { AuthMechanism } from './auth/providers';
2828
import { ScramSHA1, ScramSHA256 } from './auth/scram';
2929
import { X509 } from './auth/x509';
3030
import { CommandOptions, Connection, ConnectionOptions, CryptoConnection } from './connection';
31-
import type { ClientMetadata } from './handshake/client_metadata';
31+
import type { TruncatedClientMetadata } from './handshake/client_metadata';
3232
import {
3333
MAX_SUPPORTED_SERVER_VERSION,
3434
MAX_SUPPORTED_WIRE_VERSION,
@@ -193,7 +193,7 @@ export interface HandshakeDocument extends Document {
193193
ismaster?: boolean;
194194
hello?: boolean;
195195
helloOk?: boolean;
196-
client: ClientMetadata;
196+
client: TruncatedClientMetadata;
197197
compression: string[];
198198
saslSupportedMechs?: string;
199199
loadBalanced?: boolean;
@@ -214,7 +214,7 @@ export async function prepareHandshakeDocument(
214214
const handshakeDoc: HandshakeDocument = {
215215
[serverApi?.version ? 'hello' : LEGACY_HELLO_COMMAND]: 1,
216216
helloOk: true,
217-
client: options.metadata,
217+
client: options.truncatedClientMetadata,
218218
compression: compressors
219219
};
220220

src/cmap/connection.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import {
4545
} from './command_monitoring_events';
4646
import { BinMsg, Msg, Query, Response, WriteProtocolMessageType } from './commands';
4747
import type { Stream } from './connect';
48-
import type { ClientMetadata } from './handshake/client_metadata';
48+
import type { ClientMetadata, TruncatedClientMetadata } from './handshake/client_metadata';
4949
import { MessageStream, OperationDescription } from './message_stream';
5050
import { StreamDescription, StreamDescriptionOptions } from './stream_description';
5151
import { getReadPreference, isSharded } from './wire_protocol/shared';
@@ -128,6 +128,9 @@ export interface ConnectionOptions
128128
socketTimeoutMS?: number;
129129
cancellationToken?: CancellationToken;
130130
metadata: ClientMetadata;
131+
132+
/** @internal */
133+
truncatedClientMetadata: TruncatedClientMetadata;
131134
}
132135

133136
/** @internal */

src/cmap/connection_pool.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
227227
waitQueueTimeoutMS: options.waitQueueTimeoutMS ?? 0,
228228
minPoolSizeCheckFrequencyMS: options.minPoolSizeCheckFrequencyMS ?? 100,
229229
autoEncrypter: options.autoEncrypter,
230-
metadata: options.metadata
230+
truncatedClientMetadata: options.truncatedClientMetadata
231231
});
232232

233233
if (this.options.minPoolSize > this.options.maxPoolSize) {

src/cmap/handshake/client_metadata.ts

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { calculateObjectSize } from 'bson';
22
import * as os from 'os';
33

44
import type { MongoOptions } from '../../mongo_client';
5-
import type { DeepPartial } from '../../utils';
5+
import { deepCopy, DeepPartial } from '../../utils';
66
import { applyFaasEnvMetadata, determineCloudProvider } from './faas_provider';
77

88
/**
@@ -35,58 +35,58 @@ export interface ClientMetadata {
3535
};
3636
}
3737

38+
/** @internal */
3839
export type TruncatedClientMetadata = DeepPartial<ClientMetadata>;
3940

40-
export function truncateClientMetadata(metadata: ClientMetadata): ClientMetadata {
41-
if (calculateObjectSize(metadata) <= 512) {
42-
return metadata;
41+
export function truncateClientMetadata(metadata: ClientMetadata): TruncatedClientMetadata {
42+
const copiedMetadata: TruncatedClientMetadata = deepCopy(metadata);
43+
if (calculateObjectSize(copiedMetadata) <= 512) {
44+
return copiedMetadata;
4345
}
4446

45-
// @ts-expect-error cannot be deleted
46-
delete metadata.platform;
47+
delete copiedMetadata.platform;
4748

48-
if (calculateObjectSize(metadata) <= 512) {
49-
return metadata;
49+
if (calculateObjectSize(copiedMetadata) <= 512) {
50+
return copiedMetadata;
5051
}
5152

52-
if (metadata.env) {
53-
metadata.env = { name: metadata.env.name };
53+
if (copiedMetadata.env) {
54+
copiedMetadata.env = { name: copiedMetadata.env.name };
5455
}
5556

56-
if (calculateObjectSize(metadata) <= 512) {
57-
return metadata;
57+
if (calculateObjectSize(copiedMetadata) <= 512) {
58+
return copiedMetadata;
5859
}
5960

60-
// @ts-expect-error non-optional properties
61-
metadata.os = { type: metadata.os.type };
61+
if (copiedMetadata.os) {
62+
copiedMetadata.os = { type: copiedMetadata.os.type };
63+
}
6264

63-
if (calculateObjectSize(metadata) <= 512) {
64-
return metadata;
65+
if (calculateObjectSize(copiedMetadata) <= 512) {
66+
return copiedMetadata;
6567
}
6668

67-
delete metadata.env;
69+
delete copiedMetadata.env;
6870

69-
if (calculateObjectSize(metadata) <= 512) {
70-
return metadata;
71+
if (calculateObjectSize(copiedMetadata) <= 512) {
72+
return copiedMetadata;
7173
}
7274

73-
// @ts-expect-error required properties
74-
delete metadata.os;
75+
delete copiedMetadata.os;
7576

76-
if (calculateObjectSize(metadata) <= 512) {
77-
return metadata;
77+
if (calculateObjectSize(copiedMetadata) <= 512) {
78+
return copiedMetadata;
7879
}
7980

80-
// @ts-expect-error required properties
81-
delete metadata.driver;
81+
delete copiedMetadata.driver;
8282

83-
if (calculateObjectSize(metadata) <= 512) {
84-
return metadata;
83+
if (calculateObjectSize(copiedMetadata) <= 512) {
84+
return copiedMetadata;
8585
}
8686

87-
delete metadata.application;
87+
delete copiedMetadata.application;
8888

89-
return metadata;
89+
return copiedMetadata;
9090
}
9191

9292
/** @public */

src/connection_string.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { URLSearchParams } from 'url';
66
import type { Document } from './bson';
77
import { MongoCredentials } from './cmap/auth/mongo_credentials';
88
import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './cmap/auth/providers';
9-
import { makeClientMetadata } from './cmap/handshake/client_metadata';
9+
import { makeClientMetadata, truncateClientMetadata } from './cmap/handshake/client_metadata';
1010
import { Compressor, CompressorName } from './cmap/wire_protocol/compression';
1111
import { Encrypter } from './encrypter';
1212
import {
@@ -543,6 +543,8 @@ export function parseOptions(
543543
);
544544

545545
mongoOptions.metadata = makeClientMetadata(mongoOptions);
546+
Object.freeze(mongoOptions.metadata);
547+
mongoOptions.truncatedClientMetadata = truncateClientMetadata(mongoOptions.metadata);
546548

547549
return mongoOptions;
548550
}

src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,11 @@ export type {
238238
WaitQueueMember,
239239
WithConnectionCallback
240240
} from './cmap/connection_pool';
241-
export type { ClientMetadata, ClientMetadataOptions } from './cmap/handshake/client_metadata';
241+
export type {
242+
ClientMetadata,
243+
ClientMetadataOptions,
244+
TruncatedClientMetadata
245+
} from './cmap/handshake/client_metadata';
242246
export type {
243247
MessageStream,
244248
MessageStreamOptions,
@@ -464,6 +468,7 @@ export type { Transaction, TransactionOptions, TxnState } from './transactions';
464468
export type {
465469
BufferPool,
466470
Callback,
471+
DeepPartial,
467472
EventEmitterWithState,
468473
HostAddress,
469474
List,

src/mongo_client.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { AuthMechanismProperties, MongoCredentials } from './cmap/auth/mong
88
import type { AuthMechanism } from './cmap/auth/providers';
99
import type { LEGAL_TCP_SOCKET_OPTIONS, LEGAL_TLS_SOCKET_OPTIONS } from './cmap/connect';
1010
import type { Connection } from './cmap/connection';
11-
import type { ClientMetadata } from './cmap/handshake/client_metadata';
11+
import type { ClientMetadata, TruncatedClientMetadata } from './cmap/handshake/client_metadata';
1212
import type { CompressorName } from './cmap/wire_protocol/compression';
1313
import { parseOptions, resolveSRVRecord } from './connection_string';
1414
import { MONGO_CLIENT_EVENTS } from './constants';
@@ -712,12 +712,24 @@ export interface MongoOptions
712712
compressors: CompressorName[];
713713
writeConcern: WriteConcern;
714714
dbName: string;
715-
metadata: ClientMetadata;
716715
autoEncrypter?: AutoEncrypter;
717716
proxyHost?: string;
718717
proxyPort?: number;
719718
proxyUsername?: string;
720719
proxyPassword?: string;
720+
721+
metadata: ClientMetadata;
722+
723+
/**
724+
* @internal
725+
* `metadata` truncated to be less than 512 bytes, if necessary, to attach to handshakes.
726+
* `metadata` is left untouched because it is public and to provide users a document they
727+
* inspect to confirm their metadata was parsed correctly.
728+
*
729+
* If `metadata` `<=` 512 bytes, these fields are the same but the driver only uses `truncatedMetadata`.
730+
*/
731+
truncatedClientMetadata: TruncatedClientMetadata;
732+
721733
/** @internal */
722734
connectionType?: typeof Connection;
723735

src/sdam/topology.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { BSONSerializeOptions, Document } from '../bson';
55
import type { MongoCredentials } from '../cmap/auth/mongo_credentials';
66
import type { ConnectionEvents, DestroyOptions } from '../cmap/connection';
77
import type { CloseOptions, ConnectionPoolEvents } from '../cmap/connection_pool';
8-
import type { ClientMetadata } from '../cmap/handshake/client_metadata';
8+
import type { ClientMetadata, TruncatedClientMetadata } from '../cmap/handshake/client_metadata';
99
import { DEFAULT_OPTIONS, FEATURE_FLAGS } from '../connection_string';
1010
import {
1111
CLOSE,
@@ -138,15 +138,14 @@ export interface TopologyOptions extends BSONSerializeOptions, ServerOptions {
138138
/** The name of the replica set to connect to */
139139
replicaSet?: string;
140140
srvHost?: string;
141-
/** @internal */
142141
srvPoller?: SrvPoller;
143142
/** Indicates that a client should directly connect to a node without attempting to discover its topology type */
144143
directConnection: boolean;
145144
loadBalanced: boolean;
146145
metadata: ClientMetadata;
146+
truncatedClientMetadata: TruncatedClientMetadata;
147147
/** MongoDB server API version */
148148
serverApi?: ServerApi;
149-
/** @internal */
150149
[featureFlag: symbol]: any;
151150
}
152151

@@ -661,8 +660,8 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
661660
if (typeof callback === 'function') callback(undefined, true);
662661
}
663662

664-
get clientMetadata(): ClientMetadata {
665-
return this.s.options.metadata;
663+
get clientMetadata(): TruncatedClientMetadata {
664+
return this.s.options.truncatedClientMetadata;
666665
}
667666

668667
isConnected(): boolean {

src/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export type Callback<T = any> = (error?: AnyError, result?: T) => void;
3838

3939
export type AnyOptions = Document;
4040

41+
/** @internal */
4142
export type DeepPartial<T> = T extends object
4243
? {
4344
[P in keyof T]?: DeepPartial<T[P]>;

test/integration/mongodb-handshake/mongodb-handshake.prose.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ context('FAAS Environment Prose Tests', function () {
5858
['FUNCTIONS_WORKER_RUNTIME', 'node']
5959
]
6060
},
61-
// TODO: truncation
62-
// [
63-
// '6. Invalid - long string',
64-
// [
65-
// ['AWS_EXECUTION_ENV', 'AWS_Lambda_java8'],
66-
// ['AWS_REGION', 'a'.repeat(1024)]
67-
// ]
68-
// ],
61+
{
62+
expectedProvider: 'aws',
63+
context: '6. Invalid - long string',
64+
env: [
65+
['AWS_EXECUTION_ENV', 'AWS_Lambda_java8'],
66+
['AWS_REGION', 'a'.repeat(1024)]
67+
]
68+
},
6969
{
7070
// TODO - clarify behavior here
7171
expectedProvider: 'aws',

0 commit comments

Comments
 (0)