diff --git a/src/libraries/System.Net.ServerSentEvents/src/PACKAGE.md b/src/libraries/System.Net.ServerSentEvents/src/PACKAGE.md index dabf094e76fe7..95ad1893305b8 100644 --- a/src/libraries/System.Net.ServerSentEvents/src/PACKAGE.md +++ b/src/libraries/System.Net.ServerSentEvents/src/PACKAGE.md @@ -18,8 +18,8 @@ Asynchronously parsing event contents as strings ```csharp using HttpClient client = new(); -using Stream response = await client.GetStreamAsync("https://localhost:12345/sse"); -await foreach (SseItem item in SseParser.Create(response).EnumerateAsync()) +using Stream stream = await client.GetStreamAsync("https://localhost:12345/sse"); +await foreach (SseItem item in SseParser.Create(stream).EnumerateAsync()) { Console.WriteLine(item.Data); } @@ -29,9 +29,9 @@ Synchronously parsing event contents as JSON ```csharp MemoryStream stream = new(data); -foreach (SseItem item in SseParser.Create(response, (eventType, bytes) => JsonSerializer.Deserialize(bytes)).Enumerate()) +foreach (SseItem item in SseParser.Create(stream, (eventType, bytes) => JsonSerializer.Deserialize(bytes)).Enumerate()) { - Console.WriteLine(item.Author); + Console.WriteLine(item.Data.Author); } ``` diff --git a/src/libraries/System.Net.ServerSentEvents/src/Resources/Strings.resx b/src/libraries/System.Net.ServerSentEvents/src/Resources/Strings.resx index fd5898f283013..a0ea42d131d14 100644 --- a/src/libraries/System.Net.ServerSentEvents/src/Resources/Strings.resx +++ b/src/libraries/System.Net.ServerSentEvents/src/Resources/Strings.resx @@ -120,7 +120,4 @@ The enumerable may be enumerated only once. - - The Stream implementation is invalid, returning a negative number from a read operation. - - \ No newline at end of file + diff --git a/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/SseParser_1.cs b/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/SseParser_1.cs index 0e342d017fcf3..36de03fc72a9a 100644 --- a/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/SseParser_1.cs +++ b/src/libraries/System.Net.ServerSentEvents/src/System/Net/ServerSentEvents/SseParser_1.cs @@ -352,6 +352,7 @@ private bool ProcessLine(out SseItem sseItem, out int advance) if (fieldName.SequenceEqual("data"u8)) { // Spec: "Append the field value to the data buffer, then append a single U+000A LINE FEED (LF) character to the data buffer." + // Spec: "If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer." // If there's nothing currently in the data buffer and we can easily detect that this line is immediately followed by // an empty line, we can optimize it to just handle the data directly from the line buffer, rather than first copying @@ -462,16 +463,16 @@ private int FillLineBuffer() _lineBuffer, offset, _lineBuffer.Length - offset); #endif - if (bytesRead <= 0) + if (bytesRead > 0) + { + _lineLength += bytesRead; + } + else { _eof = true; - if (bytesRead < 0) - { - throw new InvalidOperationException(SR.InvalidOperation_InvalidStreamNegativeBytes); - } + bytesRead = 0; } - _lineLength += bytesRead; return bytesRead; } @@ -489,16 +490,16 @@ private async ValueTask FillLineBufferAsync(CancellationToken cancellationT #endif .ConfigureAwait(false); - if (bytesRead <= 0) + if (bytesRead > 0) + { + _lineLength += bytesRead; + } + else { _eof = true; - if (bytesRead < 0) - { - throw new InvalidOperationException(SR.InvalidOperation_InvalidStreamNegativeBytes); - } + bytesRead = 0; } - _lineLength += bytesRead; return bytesRead; } diff --git a/src/libraries/System.Net.ServerSentEvents/tests/SseParserTests.cs b/src/libraries/System.Net.ServerSentEvents/tests/SseParserTests.cs index 9df8e71cb980e..d8a8c3b37c1c6 100644 --- a/src/libraries/System.Net.ServerSentEvents/tests/SseParserTests.cs +++ b/src/libraries/System.Net.ServerSentEvents/tests/SseParserTests.cs @@ -726,27 +726,6 @@ public void NonGenericEnumerator_ProducesExpectedItems() Assert.False(e.MoveNext()); } - [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task InvalidStream_ReturnsNegativeValueFromRead_Throws(bool useAsync) - { - using Stream stream = new InvalidReadStream(); - - SseParser parser = SseParser.Create(stream); - - if (useAsync) - { - await using IAsyncEnumerator> e = parser.EnumerateAsync().GetAsyncEnumerator(); - await Assert.ThrowsAsync(async () => await e.MoveNextAsync()); - } - else - { - using IEnumerator> e = parser.Enumerate().GetEnumerator(); - Assert.Throws(() => e.MoveNext()); - } - } - [Theory] [MemberData(nameof(NewlineTrickleAsyncData))] public async Task MultipleItemParsers_OpenAI_StreamingResponse(string newline, bool trickle, bool useAsync) @@ -978,23 +957,6 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation await Task.Yield(); return await base.ReadAsync(buffer.Slice(0, Math.Min(buffer.Length, 1)), cancellationToken); } -#endif - } - - private sealed class InvalidReadStream : MemoryStream - { - public override int Read(byte[] buffer, int offset, int count) => - -1; - - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => - Task.FromResult(-1); - -#if NET - public override int Read(Span buffer) => - -1; - - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) => - ValueTask.FromResult(-1); #endif } }