From 7d83e4e94170fce8721ddcb2e286cd1750f2ca8d Mon Sep 17 00:00:00 2001 From: Gregor Bigalke Date: Mon, 22 Dec 2025 21:17:09 +0100 Subject: [PATCH 1/4] fix buffer slice handling and serialization --- src/protocol/header.ts | 2 +- src/protocol/message.ts | 25 +++++++++++++------------ src/protocol/protocol.ts | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/protocol/header.ts b/src/protocol/header.ts index 20fb8b69..645f7055 100644 --- a/src/protocol/header.ts +++ b/src/protocol/header.ts @@ -28,7 +28,7 @@ export function setHeader( } export function parseHeader(buffer: Uint8Array): MessageHeader { - const view = new DataView(buffer.buffer); + const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); return { messageLength: view.getUint32(0, true), requestId: view.getUint32(4, true), diff --git a/src/protocol/message.ts b/src/protocol/message.ts index 38ec7215..2249010d 100644 --- a/src/protocol/message.ts +++ b/src/protocol/message.ts @@ -53,8 +53,13 @@ function serializeSections( view.setUint8(0, 1); view.setUint32(1, section1.byteLength - 1, true); - let pos = 4; + let pos = 5; + // write identifuer + section1.set(identifier, pos); + pos += identifier.byteLength; + + // write documents for (const doc of docs) { section1.set(doc, pos); pos += doc.byteLength; @@ -103,29 +108,25 @@ export function deserializeMessage( header: MessageHeader, buffer: Uint8Array, ): Message { - const view = new DataView(buffer.buffer); + const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); - const flags = view.getInt32(0); + const flags = view.getInt32(0, true); const sections: Section[] = []; let pos = 4; - while (pos < view.byteLength) { + while (pos < buffer.byteLength) { const kind = view.getInt8(pos); pos++; if (kind === 0) { const docLen = view.getInt32(pos, true); - const document = deserialize( - new Uint8Array(view.buffer.slice(pos, pos + docLen)), - ); + const document = deserialize(buffer.slice(pos, pos + docLen)); pos += docLen; sections.push({ document }); } else if (kind === 1) { const len = view.getInt32(pos, true); - const sectionBody = new Uint8Array( - view.buffer.slice(pos + 4, pos + len - 4), - ); + const sectionBody = buffer.slice(pos + 4, pos + len); const identifierEndPos = sectionBody.findIndex((byte) => byte === 0); - const identifier = decoder.decode(buffer.slice(0, identifierEndPos)); + const identifier = decoder.decode(sectionBody.slice(0, identifierEndPos)); const docsBuffer = sectionBody.slice(identifierEndPos + 1); const documents = parseDocuments(docsBuffer); pos += len; @@ -146,7 +147,7 @@ export function deserializeMessage( function parseDocuments(buffer: Uint8Array): Document[] { let pos = 0; const docs = []; - const view = new DataView(buffer.buffer); + const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); while (pos < buffer.byteLength) { const docLen = view.getInt32(pos, true); const doc = deserialize(buffer.slice(pos, pos + docLen)); diff --git a/src/protocol/protocol.ts b/src/protocol/protocol.ts index 51aad19c..cd79ed83 100644 --- a/src/protocol/protocol.ts +++ b/src/protocol/protocol.ts @@ -150,8 +150,20 @@ export class WireProtocol { b: number, ): Promise { const reader = this.#conn.readable.getReader({ mode: "byob" }); - const { value } = await reader.read(new Uint8Array(b)); + const result = new Uint8Array(b); + let offset = 0; + + while (offset < b) { + const { value, done } = await reader.read(new Uint8Array(b - offset)); + if (done || !value) { + reader.releaseLock(); + return undefined; + } + result.set(value, offset); + offset += value.byteLength; + } + reader.releaseLock(); - return value; + return result; } } From 21f1cff3b164e0473dccdb1ebe0eaab7fbed2e9a Mon Sep 17 00:00:00 2001 From: Gregor Bigalke Date: Mon, 22 Dec 2025 21:26:51 +0100 Subject: [PATCH 2/4] fix ci --- src/auth/pbkdf2.ts | 4 ++-- src/protocol/header.ts | 6 +++++- src/protocol/message.ts | 12 ++++++++++-- tests/cases/03_crud.ts | 2 +- tests/deps.ts | 1 + 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/auth/pbkdf2.ts b/src/auth/pbkdf2.ts index 59879448..1552a0eb 100644 --- a/src/auth/pbkdf2.ts +++ b/src/auth/pbkdf2.ts @@ -31,8 +31,8 @@ export async function pbkdf2( return crypto.subtle.deriveBits( { name: "PBKDF2", - salt: salt, - iterations: iterations, + salt: salt as BufferSource, + iterations, hash: { name: algo, }, diff --git a/src/protocol/header.ts b/src/protocol/header.ts index 645f7055..44c65e18 100644 --- a/src/protocol/header.ts +++ b/src/protocol/header.ts @@ -28,7 +28,11 @@ export function setHeader( } export function parseHeader(buffer: Uint8Array): MessageHeader { - const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); + const view = new DataView( + buffer.buffer, + buffer.byteOffset, + buffer.byteLength, + ); return { messageLength: view.getUint32(0, true), requestId: view.getUint32(4, true), diff --git a/src/protocol/message.ts b/src/protocol/message.ts index 2249010d..4ebe9184 100644 --- a/src/protocol/message.ts +++ b/src/protocol/message.ts @@ -108,7 +108,11 @@ export function deserializeMessage( header: MessageHeader, buffer: Uint8Array, ): Message { - const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); + const view = new DataView( + buffer.buffer, + buffer.byteOffset, + buffer.byteLength, + ); const flags = view.getInt32(0, true); const sections: Section[] = []; @@ -147,7 +151,11 @@ export function deserializeMessage( function parseDocuments(buffer: Uint8Array): Document[] { let pos = 0; const docs = []; - const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); + const view = new DataView( + buffer.buffer, + buffer.byteOffset, + buffer.byteLength, + ); while (pos < buffer.byteLength) { const docLen = view.getInt32(pos, true); const doc = deserialize(buffer.slice(pos, pos + docLen)); diff --git a/tests/cases/03_crud.ts b/tests/cases/03_crud.ts index 3979c6d1..807b30cc 100644 --- a/tests/cases/03_crud.ts +++ b/tests/cases/03_crud.ts @@ -1,4 +1,3 @@ -import { assertInstanceOf } from "jsr:@std/assert@^0.220.1/assert_instance_of"; import type { Database, MongoClient, ObjectId } from "../../mod.ts"; import { MongoInvalidArgumentError, @@ -10,6 +9,7 @@ import { afterEach, assert, assertEquals, + assertInstanceOf, assertRejects, beforeEach, describe, diff --git a/tests/deps.ts b/tests/deps.ts index 77e65657..1d7fad6a 100644 --- a/tests/deps.ts +++ b/tests/deps.ts @@ -1,6 +1,7 @@ export { assert, assertEquals, + assertInstanceOf, assertNotEquals, assertRejects, assertThrows, From 794fe39a5d8450146f4bea2df0c835184e6f3118 Mon Sep 17 00:00:00 2001 From: Gregor Bigalke Date: Mon, 22 Dec 2025 21:41:04 +0100 Subject: [PATCH 3/4] use deno's min attribute --- src/protocol/protocol.ts | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/protocol/protocol.ts b/src/protocol/protocol.ts index cd79ed83..432e90d8 100644 --- a/src/protocol/protocol.ts +++ b/src/protocol/protocol.ts @@ -150,20 +150,8 @@ export class WireProtocol { b: number, ): Promise { const reader = this.#conn.readable.getReader({ mode: "byob" }); - const result = new Uint8Array(b); - let offset = 0; - - while (offset < b) { - const { value, done } = await reader.read(new Uint8Array(b - offset)); - if (done || !value) { - reader.releaseLock(); - return undefined; - } - result.set(value, offset); - offset += value.byteLength; - } - + const { value } = await reader.read(new Uint8Array(b), { min: b }); reader.releaseLock(); - return result; + return value; } } From 4bc09cff02b32d22093660b98828ce8c0ab1fa3b Mon Sep 17 00:00:00 2001 From: Gregor Bigalke Date: Mon, 22 Dec 2025 21:46:42 +0100 Subject: [PATCH 4/4] BufferSource for salt --- src/auth/pbkdf2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth/pbkdf2.ts b/src/auth/pbkdf2.ts index 1552a0eb..e6c53ba4 100644 --- a/src/auth/pbkdf2.ts +++ b/src/auth/pbkdf2.ts @@ -31,7 +31,7 @@ export async function pbkdf2( return crypto.subtle.deriveBits( { name: "PBKDF2", - salt: salt as BufferSource, + salt: salt.buffer as ArrayBuffer, iterations, hash: { name: algo,