From 6adc5a55e4b90c2206e4d31bcc170597530554db Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 20 Nov 2024 18:27:27 -0500 Subject: [PATCH 1/2] Fix PooledByteBufferWriter handling of sizeHint <= 0 --- .../PooledByteBufferWriter.cs | 4 +-- .../tests/SseFormatterTests.cs | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs b/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs index 81e5070b765d0..3258ded10da37 100644 --- a/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs +++ b/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs @@ -14,13 +14,13 @@ internal sealed class PooledByteBufferWriter : IBufferWriter, IDisposable public Memory GetMemory(int sizeHint = 0) { - _buffer.EnsureAvailableSpace(sizeHint); + _buffer.EnsureAvailableSpace(Math.Max(sizeHint, 1)); return _buffer.AvailableMemory; } public Span GetSpan(int sizeHint = 0) { - _buffer.EnsureAvailableSpace(sizeHint); + _buffer.EnsureAvailableSpace(Math.Max(sizeHint, 1)); return _buffer.AvailableSpan; } diff --git a/src/libraries/System.Net.ServerSentEvents/tests/SseFormatterTests.cs b/src/libraries/System.Net.ServerSentEvents/tests/SseFormatterTests.cs index a21f74f8cacb2..a71acf2099848 100644 --- a/src/libraries/System.Net.ServerSentEvents/tests/SseFormatterTests.cs +++ b/src/libraries/System.Net.ServerSentEvents/tests/SseFormatterTests.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; @@ -117,6 +118,35 @@ async IAsyncEnumerable> GetItemsAsync([EnumeratorCancellation] C } } + [Fact] + public static async Task WriteLargeItems_DataWrittenSuccessfully() + { + const int NumberOfItems = 10; + byte[] expected = Encoding.UTF8.GetBytes(string.Concat(Enumerable.Repeat("This is a test. This is only a test.", 100))); + + MemoryStream memoryStream = new(); + await SseFormatter.WriteAsync(GetBuffersAsync(), memoryStream, (item, writer) => writer.Write(item.Data)); + + memoryStream.Position = 0; + int count = 0; + foreach (SseItem item in SseParser.Create(memoryStream, (eventType, data) => data.ToArray()).Enumerate()) + { + Assert.Equal(expected, item.Data); + count++; + } + + Assert.Equal(NumberOfItems, count); + + async IAsyncEnumerable> GetBuffersAsync() + { + await Task.Yield(); + for (int i = 0; i < NumberOfItems; i++) + { + yield return new SseItem(expected); + } + } + } + [Fact] public static async Task WriteAsync_ParserCanRoundtripJsonEvents() { From 87107e401583ba6d2ecd46931962dd14d7d43e0e Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 20 Nov 2024 18:41:31 -0500 Subject: [PATCH 2/2] Add MinimumBufferSize constant and update usage --- .../System/Net/ServerSentEvents/PooledByteBufferWriter.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs b/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs index 3258ded10da37..15df82ba2f2ce 100644 --- a/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs +++ b/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/PooledByteBufferWriter.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; @@ -8,19 +8,20 @@ namespace System.Net.ServerSentEvents { internal sealed class PooledByteBufferWriter : IBufferWriter, IDisposable { + private const int MinimumBufferSize = 256; private ArrayBuffer _buffer = new(initialSize: 256, usePool: true); public void Advance(int count) => _buffer.Commit(count); public Memory GetMemory(int sizeHint = 0) { - _buffer.EnsureAvailableSpace(Math.Max(sizeHint, 1)); + _buffer.EnsureAvailableSpace(Math.Max(sizeHint, MinimumBufferSize)); return _buffer.AvailableMemory; } public Span GetSpan(int sizeHint = 0) { - _buffer.EnsureAvailableSpace(Math.Max(sizeHint, 1)); + _buffer.EnsureAvailableSpace(Math.Max(sizeHint, MinimumBufferSize)); return _buffer.AvailableSpan; }