@@ -44,9 +44,9 @@ public abstract partial class Frame : FrameContext, IFrameControl
44
44
protected readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders ( ) ;
45
45
private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders ( ) ;
46
46
47
- private List < KeyValuePair < Func < object , Task > , object > > _onStarting ;
47
+ protected List < KeyValuePair < Func < object , Task > , object > > _onStarting ;
48
48
49
- private List < KeyValuePair < Func < object , Task > , object > > _onCompleted ;
49
+ protected List < KeyValuePair < Func < object , Task > , object > > _onCompleted ;
50
50
51
51
private bool _requestProcessingStarted ;
52
52
private Task _requestProcessingTask ;
@@ -144,8 +144,9 @@ public CancellationToken RequestAborted
144
144
{
145
145
// If a request abort token was previously explicitly set, return it.
146
146
if ( _manuallySetRequestAbortToken . HasValue )
147
+ {
147
148
return _manuallySetRequestAbortToken . Value ;
148
-
149
+ }
149
150
// Otherwise, get the abort CTS. If we have one, which would mean that someone previously
150
151
// asked for the RequestAborted token, simply return its token. If we don't,
151
152
// check to see whether we've already aborted, in which case just return an
@@ -416,7 +417,28 @@ public void Write(ArraySegment<byte> data)
416
417
}
417
418
}
418
419
419
- public async Task WriteAsync ( ArraySegment < byte > data , CancellationToken cancellationToken )
420
+ public Task WriteAsync ( ArraySegment < byte > data , CancellationToken cancellationToken )
421
+ {
422
+ if ( ! _responseStarted )
423
+ {
424
+ return WriteAsyncAwaited ( data , cancellationToken ) ;
425
+ }
426
+
427
+ if ( _autoChunk )
428
+ {
429
+ if ( data . Count == 0 )
430
+ {
431
+ return TaskUtilities . CompletedTask ;
432
+ }
433
+ return WriteChunkedAsync ( data , cancellationToken ) ;
434
+ }
435
+ else
436
+ {
437
+ return SocketOutput . WriteAsync ( data , immediate : true , cancellationToken : cancellationToken ) ;
438
+ }
439
+ }
440
+
441
+ public async Task WriteAsyncAwaited ( ArraySegment < byte > data , CancellationToken cancellationToken )
420
442
{
421
443
await ProduceStartAndFireOnStarting ( immediate : false ) ;
422
444
@@ -501,10 +523,27 @@ public void ProduceContinue()
501
523
}
502
524
}
503
525
504
- public async Task ProduceStartAndFireOnStarting ( bool immediate = true )
526
+ public Task ProduceStartAndFireOnStarting ( bool immediate = true )
505
527
{
506
- if ( _responseStarted ) return ;
528
+ if ( _responseStarted ) return TaskUtilities . CompletedTask ;
529
+
530
+ if ( _onStarting != null )
531
+ {
532
+ return FireOnStartingProduceStart ( immediate : immediate ) ;
533
+ }
507
534
535
+ if ( _applicationException != null )
536
+ {
537
+ throw new ObjectDisposedException (
538
+ "The response has been aborted due to an unhandled application exception." ,
539
+ _applicationException ) ;
540
+ }
541
+
542
+ return ProduceStart ( immediate , appCompleted : false ) ;
543
+ }
544
+
545
+ private async Task FireOnStartingProduceStart ( bool immediate )
546
+ {
508
547
await FireOnStarting ( ) ;
509
548
510
549
if ( _applicationException != null )
@@ -527,15 +566,15 @@ private Task ProduceStart(bool immediate, bool appCompleted)
527
566
return CreateResponseHeader ( statusBytes , appCompleted , immediate ) ;
528
567
}
529
568
530
- protected async Task ProduceEnd ( )
569
+ protected Task ProduceEnd ( )
531
570
{
532
571
if ( _applicationException != null )
533
572
{
534
573
if ( _responseStarted )
535
574
{
536
575
// We can no longer respond with a 500, so we simply close the connection.
537
576
_requestProcessingStopping = true ;
538
- return ;
577
+ return TaskUtilities . CompletedTask ;
539
578
}
540
579
else
541
580
{
@@ -547,8 +586,26 @@ protected async Task ProduceEnd()
547
586
}
548
587
}
549
588
589
+
590
+ if ( ! _responseStarted )
591
+ {
592
+ return ProduceEndAwaited ( ) ;
593
+ }
594
+
595
+ WriteSuffix ( ) ;
596
+
597
+ return TaskUtilities . CompletedTask ;
598
+ }
599
+
600
+ private async Task ProduceEndAwaited ( )
601
+ {
550
602
await ProduceStart ( immediate : true , appCompleted : true ) ;
551
603
604
+ WriteSuffix ( ) ;
605
+ }
606
+
607
+ private void WriteSuffix ( )
608
+ {
552
609
// _autoChunk should be checked after we are sure ProduceStart() has been called
553
610
// since ProduceStart() may set _autoChunk to true.
554
611
if ( _autoChunk )
0 commit comments