11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ using System . IO . Pipelines ;
45using System . Net . ServerSentEvents ;
56using System . Reflection ;
67using System . Runtime . CompilerServices ;
78using System . Text ;
9+ using Castle . DynamicProxy . Generators . Emitters . SimpleAST ;
810using Microsoft . AspNetCore . Builder ;
11+ using Microsoft . AspNetCore . Http . Features ;
912using Microsoft . AspNetCore . Http . Json ;
1013using Microsoft . AspNetCore . Http . Metadata ;
1114using Microsoft . AspNetCore . Routing ;
@@ -31,6 +34,7 @@ public async Task ExecuteAsync_SetsContentTypeAndHeaders()
3134 Assert . Equal ( "text/event-stream" , httpContext . Response . ContentType ) ;
3235 Assert . Equal ( "no-cache,no-store" , httpContext . Response . Headers . CacheControl ) ;
3336 Assert . Equal ( "no-cache" , httpContext . Response . Headers . Pragma ) ;
37+ Assert . Equal ( "identity" , httpContext . Response . Headers . ContentEncoding ) ;
3438 }
3539
3640 [ Fact ]
@@ -259,6 +263,75 @@ async IAsyncEnumerable<string> GetEvents([EnumeratorCancellation] CancellationTo
259263 }
260264 }
261265
266+ [ Fact ]
267+ public async Task ExecuteAsync_DisablesBuffering ( )
268+ {
269+ // Arrange
270+ var httpContext = GetHttpContext ( ) ;
271+ var events = AsyncEnumerable . Empty < string > ( ) ;
272+ var result = TypedResults . ServerSentEvents ( events ) ;
273+ var bufferingDisabled = false ;
274+
275+ var mockBufferingFeature = new MockHttpResponseBodyFeature (
276+ onDisableBuffering : ( ) => bufferingDisabled = true ) ;
277+
278+ httpContext . Features . Set < IHttpResponseBodyFeature > ( mockBufferingFeature ) ;
279+
280+ // Act
281+ await result . ExecuteAsync ( httpContext ) ;
282+
283+ // Assert
284+ Assert . True ( bufferingDisabled ) ;
285+ }
286+
287+ [ Fact ]
288+ public async Task ExecuteAsync_WithByteArrayData_WritesDataDirectly ( )
289+ {
290+ // Arrange
291+ var httpContext = GetHttpContext ( ) ;
292+ var bytes = "event1"u8 . ToArray ( ) ;
293+ var events = new [ ] { new SseItem < byte [ ] > ( bytes ) } . ToAsyncEnumerable ( ) ;
294+ var result = TypedResults . ServerSentEvents ( events ) ;
295+
296+ // Act
297+ await result . ExecuteAsync ( httpContext ) ;
298+
299+ // Assert
300+ var responseBody = Encoding . UTF8 . GetString ( ( ( MemoryStream ) httpContext . Response . Body ) . ToArray ( ) ) ;
301+ Assert . Contains ( "data: event1\n \n " , responseBody ) ;
302+
303+ // Assert that string is not JSON serialized
304+ Assert . DoesNotContain ( "data: \" event1" , responseBody ) ;
305+ }
306+
307+ [ Fact ]
308+ public async Task ExecuteAsync_WithByteArrayData_HandlesNullData ( )
309+ {
310+ // Arrange
311+ var httpContext = GetHttpContext ( ) ;
312+ var events = new [ ] { new SseItem < byte [ ] > ( null ) } . ToAsyncEnumerable ( ) ;
313+ var result = TypedResults . ServerSentEvents ( events ) ;
314+
315+ // Act
316+ await result . ExecuteAsync ( httpContext ) ;
317+
318+ // Assert
319+ var responseBody = Encoding . UTF8 . GetString ( ( ( MemoryStream ) httpContext . Response . Body ) . ToArray ( ) ) ;
320+ Assert . Contains ( "data: \n \n " , responseBody ) ;
321+ }
322+
323+ private class MockHttpResponseBodyFeature ( Action onDisableBuffering ) : IHttpResponseBodyFeature
324+ {
325+ public Stream Stream => new MemoryStream ( ) ;
326+ public PipeWriter Writer => throw new NotImplementedException ( ) ;
327+ public Task CompleteAsync ( ) => throw new NotImplementedException ( ) ;
328+ public void DisableBuffering ( ) => onDisableBuffering ( ) ;
329+ public Task SendFileAsync ( string path , long offset , long ? count , CancellationToken cancellationToken = default )
330+ => throw new NotImplementedException ( ) ;
331+ public Task StartAsync ( CancellationToken cancellationToken = default )
332+ => throw new NotImplementedException ( ) ;
333+ }
334+
262335 private static void PopulateMetadata < TResult > ( MethodInfo method , EndpointBuilder builder )
263336 where TResult : IEndpointMetadataProvider => TResult . PopulateMetadata ( method , builder ) ;
264337
0 commit comments