Measure size of string fields in UTF-8 bytes for maxMessageSize accounting - #2289
Measure size of string fields in UTF-8 bytes for maxMessageSize accounting#2289sacOO7 wants to merge 1 commit into
Conversation
The client-side maxMessageSize gate undercounted non-ASCII clientIds and LiveObjects map keys by measuring them in UTF-16 code units (.length), while the server accounts for them in UTF-8 bytes. This false-accepted boundary messages the server would reject, and diverged from ably-java/ably-cocoa (which already counted UTF-8). - src/plugins/liveobjects/objectmessage.ts: clientId (OM3f), OMP4a1, MCR3a1, MST3c, MRM3a now use this._utils.dataSizeBytes(...) (UTF-8). extras stays JSON.stringify(...).length (UTF-16); ObjectData (OD3b-g) already used dataSizeBytes. - src/common/lib/types/message.ts (getMessageSize): name and clientId now use Utils.dataSizeBytes(...) (UTF-8). extras stays JSON.stringify(...).length. - test/realtime/liveobjects.test.js: +6 non-ASCII ObjectMessage size scenarios (OM3f/MCR3a1/MST3c/MRM3a/OMP4a1 UTF-8; OM3d UTF-16). Aligns with ably/specification (UTF-8 byte length default, extras as UTF-16 string length of its JSON representation).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
WalkthroughThe change updates message and LiveObjects size calculations to use UTF-8 byte lengths for names, client IDs, and map keys. Realtime tests add non-ASCII scenarios and preserve UTF-16 JSON length handling for extras. ChangesMessage size accounting
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Tools execution failed with the following error: Failed to run tools: 14 UNAVAILABLE: read ECONNRESET Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Aligns client-side maxMessageSize publish-gate accounting with Ably’s documented/server behavior by measuring relevant string fields using their UTF-8 byte length (instead of JS UTF-16 code unit length), preventing false-accepts for non-ASCII content and reducing cross-SDK divergence.
Changes:
- Update regular
Messagesize calculation to measurenameandclientIdusingUtils.dataSizeBytes(UTF-8 bytes). - Update LiveObjects
WireObjectMessagesize calculation to measureclientIdand map/operation keys usingdataSizeBytes(UTF-8 bytes), keepingextrasmeasured viaJSON.stringify(...).length. - Add LiveObjects tests covering non-ASCII scenarios to lock in the intended accounting rules.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/common/lib/types/message.ts |
Switch name/clientId sizing to UTF-8 byte length for regular Message maxMessageSize accounting. |
src/plugins/liveobjects/objectmessage.ts |
Switch LiveObjects clientId and key sizing to UTF-8 byte length for object message maxMessageSize accounting. |
test/realtime/liveobjects.test.js |
Add non-ASCII ObjectMessage size scenarios validating UTF-8 sizing for strings/keys and UTF-16 JSON string length for extras. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let size = 0; | ||
| if (msg.name) { | ||
| size += msg.name.length; | ||
| size += Utils.dataSizeBytes(msg.name); // UTF-8 byte length |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/common/lib/types/message.ts:46
- Add non-ASCII coverage for the regular
Messagepath changed here. The new scenarios only exerciseWireObjectMessage.getMessageSize(), while the existing regular-messagemaxMessageSizetests use ASCII payloads, so neither thenamenorclientIdUTF-8 accounting is verified at the publish boundary. A boundary test with你😊should assert the local 40009 decision for these fields.
size += Utils.dataSizeBytes(msg.name); // UTF-8 byte length
}
if (msg.clientId) {
size += Utils.dataSizeBytes(msg.clientId); // UTF-8 byte length
Problem
The client-side
maxMessageSizepublish gate sums per-field sizes and rejects an over-limit publish before it hits the wire. ably-js measured string fields (clientId, LiveObjects map/operation keys) by their UTF-16 code-unit count (.length), but the server accounts for these fields in UTF-8 bytes. For ASCII these coincide; for non-ASCII they diverge (你= 3 UTF-8 bytes / 1 UTF-16 code unit;😊= 4 UTF-8 bytes / 2 UTF-16 code units), so js undercounted.Ably's published accounting — How is maximum message size measured? — is explicit:
Consequences of the undercount:
40009/40006) — or drop the connection — instead of being cleanly rejected locally.clientId/key was accepted by js but rejected by ably-java / ably-cocoa (which already counted UTF-8) — one publish, two verdicts.Spec disambiguation (anchor PR): ably/specification#516. History / earlier attempt: ably/specification#331.
Solution
Measure string fields in UTF-8 bytes via the existing
Utils.dataSizeBytes(TextEncoder/Buffer.byteLength), matching the server.extrasis deliberately unchanged — the published accounting has an explicit distinct rule for it ("string length of its JSON representation", i.e. UTF-16 code units), and measuringextrasin UTF-8 would over-count and false-reject documented-valid messages.Sites changed:
src/plugins/liveobjects/objectmessage.ts— 5 sites?.length→dataSizeBytes(...):clientId(OM3f),OMP4a1(map-state key),MCR3a1,MST3c,MRM3a(operation keys).extrasstaysJSON.stringify(...).length;ObjectData(OD3b–g) already useddataSizeBytes.src/common/lib/types/message.ts(getMessageSize) —nameandclientId.length→Utils.dataSizeBytes(...)(UTF-8).extrasstaysJSON.stringify(...).length.Tests
test/realtime/liveobjects.test.js— +6 non-ASCIIObjectMessagesize scenarios (clientId = '你😊'etc.) locking the convention:OM3f/MCR3a1/MST3c/MRM3a/OMP4a1asserted againstUtils.dataSizeBytes(...)(UTF-8),OM3d(extras) asserted againstJSON.stringify(...).length(UTF-16).Verification
npm run build:node— clean.npx tsc --noEmit -p tsconfig.json— 0 errors.mocha test/realtime/liveobjects.test.js --grep "message size"— 37 passing (incl. the 6 new non-ASCII scenarios).Notes
Follow-up: the
name/clientIdUTF-8 change ingetMessageSize(regularMessage) has no dedicated non-ASCII unit test yet — the new scenarios cover the LiveObjectsObjectMessagepath only. Worth adding one alongside the regular-Message size tests.Summary by CodeRabbit
Bug Fixes
Tests