Skip to content

Commit ba941d4

Browse files
JsonRpc: write frame header straight into the pooled buffer
BuildFrame stackalloc'd a header scratch then copied it into the rented frame. Over-rent by the fixed <=30B header bound instead and write the header directly into the frame, dropping the scratch buffer and header copy. The single JSON copy remains (its length must precede it as Content-Length). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 396870f commit ba941d4

1 file changed

Lines changed: 7 additions & 5 deletions

File tree

dotnet/src/JsonRpc.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,16 @@ private static byte[] BuildFrame(ReadOnlySpan<byte> json, out int frameLen)
241241
// "Content-Length: " (16) + max int digits (10) + "\r\n\r\n" (4)
242242
const int MaxHeaderLength = 30;
243243

244-
Span<byte> header = stackalloc byte[MaxHeaderLength];
245-
bool wrote = Utf8.TryWrite(header, $"Content-Length: {json.Length}\r\n\r\n", out int headerLen);
244+
// Over-rent by the (fixed, tiny) header bound so the header can be written
245+
// straight into the frame — no scratch buffer or header copy. The JSON is
246+
// already UTF-8, so the only copy is placing it after the header, which is
247+
// unavoidable since Content-Length needs its length up front.
248+
var frame = ArrayPool<byte>.Shared.Rent(MaxHeaderLength + json.Length);
249+
bool wrote = Utf8.TryWrite(frame, $"Content-Length: {json.Length}\r\n\r\n", out int headerLen);
246250
Debug.Assert(wrote && headerLen > 0);
247251

248-
frameLen = headerLen + json.Length;
249-
var frame = ArrayPool<byte>.Shared.Rent(frameLen);
250-
header.Slice(0, headerLen).CopyTo(frame);
251252
json.CopyTo(frame.AsSpan(headerLen));
253+
frameLen = headerLen + json.Length;
252254
return frame;
253255
}
254256

0 commit comments

Comments
 (0)