From cf97eab3960fb5fe119ce25d1203f8fcc3d38ff2 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 5 May 2026 19:36:38 -0400 Subject: [PATCH] [M5] mxaccess-asb: collect_asbidata_payloads concatenates chunked Bytes records MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .NET's `XmlBinaryWriter.WriteBase64` chunks the byte array into multiple consecutive NBFX `Bytes8/16/32` records when the total exceeds the per-record budget. Live capture of a successful .NET RegisterItemsResponse showed the Status ASBIData payload split into `Bytes8(78) + Bytes8WithEndElement(1)` — total 79 bytes. Our decoder walked tokens looking for a single `Text(Bytes(...))` after each `` element and stopped at the first chunk, returning a truncated payload that hit `Codec(ShortRead)` when the consumer tried to decode an ItemStatus from the partial bytes. Fix: walk **all** consecutive `Text(Bytes)` tokens after `` and concatenate into a single payload before pushing to the result vector. Mirrors WCF's reader behaviour, which reassembles the chunks into one byte array via `XmlReader.ReadElementContentAsBase64`. Workspace: 710 unit tests pass. Live state: AuthenticateMe is accepted, RegisterItemsResponse decodes structurally — the remaining "MissingField Status" error reflects a server-side semantic outcome (server returned empty Status array) rather than a protocol bug, likely tag-resolution related and outside F28's scope. Co-Authored-By: Claude Opus 4.7 (1M context) --- rust/crates/mxaccess-asb/src/operations.rs | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/rust/crates/mxaccess-asb/src/operations.rs b/rust/crates/mxaccess-asb/src/operations.rs index cdb41e6..cba9fb2 100644 --- a/rust/crates/mxaccess-asb/src/operations.rs +++ b/rust/crates/mxaccess-asb/src/operations.rs @@ -1157,8 +1157,30 @@ pub fn collect_asbidata_payloads(tokens: &[NbfxToken]) -> Vec> { ) { inner += 1; } - if let Some(NbfxToken::Text(NbfxText::Bytes(payload))) = tokens.get(inner) { - out.push(payload.clone()); + // CONCATENATE all consecutive `Bytes` text records. + // .NET's `XmlBinaryWriter.WriteBase64` chunks the byte + // array into multiple NBFX `Bytes8/16/32` records when + // the total exceeds the per-record budget — captured + // live response showed an ASBIData payload split into + // a Bytes8(78) + Bytes8WithEndElement(1) pair, total + // 79 bytes. Earlier we only returned the first chunk + // and the consumer hit a `ShortRead` decoding the + // truncated ItemStatus. The decoder collapses adjacent + // Bytes-followed-by-Bytes pairs into a single text + // token, but a `Bytes`-then-`EndElement` (from the + // `WithEndElement` variant) leaves a sequence of + // `Bytes` tokens we walk here. + let mut combined: Option> = None; + while let Some(NbfxToken::Text(NbfxText::Bytes(payload))) = tokens.get(inner) + { + match combined.as_mut() { + Some(buf) => buf.extend_from_slice(payload), + None => combined = Some(payload.clone()), + } + inner += 1; + } + if let Some(buf) = combined { + out.push(buf); } } }