Skip to content

Commit fdf96e3

Browse files
committed
fb
1 parent 000f75d commit fdf96e3

File tree

3 files changed

+49
-40
lines changed

3 files changed

+49
-40
lines changed

src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ private void WriteResponseHeadersInternal(ref BufferWriter<PipeWriter> writer, i
360360

361361
writer.Commit();
362362

363+
Debug.Assert(responseBodyMode != ResponseBodyMode.Uninitialized);
363364
_responseBodyMode = responseBodyMode;
364365
WriteDataWrittenBeforeHeaders(ref writer);
365366
_unflushedBytes += writer.BytesCommitted;
@@ -544,7 +545,7 @@ public void Reset()
544545
Debug.Assert(_completedSegments == null || _completedSegments.Count == 0);
545546
// Cleared in sequential address ascending order
546547
_currentMemoryPrefixBytes = 0;
547-
_responseBodyMode = ResponseBodyMode.ContentLength;
548+
_responseBodyMode = ResponseBodyMode.Uninitialized;
548549
_writeStreamSuffixCalled = false;
549550
_currentChunkMemoryUpdated = false;
550551
_startCalled = false;

src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ internal abstract partial class HttpProtocol : IHttpResponseControl
5656
protected volatile bool _keepAlive = true;
5757
// _responseBodyMode is set in CreateResponseHeaders.
5858
// If we are writing with GetMemory/Advance before calling StartAsync, assume we can write and throw away contents if we can't.
59-
private ResponseBodyMode _responseBodyMode = ResponseBodyMode.ContentLength;
59+
private ResponseBodyMode _responseBodyMode = ResponseBodyMode.Uninitialized;
6060
private bool _hasAdvanced;
6161
private bool _isLeasedMemoryInvalid = true;
6262
protected Exception? _applicationException;
@@ -346,7 +346,7 @@ public void Reset()
346346
_routeValues?.Clear();
347347

348348
_requestProcessingStatus = RequestProcessingStatus.RequestPending;
349-
_responseBodyMode = ResponseBodyMode.ContentLength;
349+
_responseBodyMode = ResponseBodyMode.Uninitialized;
350350
_applicationException = null;
351351
_requestRejectedException = null;
352352

@@ -1592,28 +1592,28 @@ public ValueTask<FlushResult> WritePipeAsync(ReadOnlyMemory<byte> data, Cancella
15921592
VerifyAndUpdateWrite(data.Length);
15931593
}
15941594

1595-
if (_responseBodyMode != ResponseBodyMode.Disabled)
1595+
switch (_responseBodyMode)
15961596
{
1597-
if (_responseBodyMode == ResponseBodyMode.Chunked)
1598-
{
1597+
case ResponseBodyMode.Disabled:
1598+
HandleNonBodyResponseWrite();
1599+
return default;
1600+
case ResponseBodyMode.Chunked:
15991601
if (data.Length == 0)
16001602
{
16011603
return default;
16021604
}
16031605

16041606
return Output.WriteChunkAsync(data.Span, cancellationToken);
1605-
}
1606-
else
1607-
{
1607+
case ResponseBodyMode.ContentLength:
16081608
CheckLastWrite();
16091609
return Output.WriteDataToPipeAsync(data.Span, cancellationToken: cancellationToken);
1610-
}
1611-
}
1612-
else
1613-
{
1614-
HandleNonBodyResponseWrite();
1615-
return default;
1610+
case ResponseBodyMode.Uninitialized:
1611+
ThrowInvalidOperation();
1612+
break;
16161613
}
1614+
1615+
Debug.Assert(false, "Should not reach here, all cases in above switch statement should return");
1616+
return default;
16171617
}
16181618

16191619
private ValueTask<FlushResult> FirstWriteAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
@@ -1640,30 +1640,30 @@ private ValueTask<FlushResult> FirstWriteAsyncInternal(ReadOnlyMemory<byte> data
16401640
{
16411641
var responseHeaders = InitializeResponseFirstWrite(data.Length);
16421642

1643-
if (_responseBodyMode != ResponseBodyMode.Disabled)
1643+
switch (_responseBodyMode)
16441644
{
1645-
if (_responseBodyMode == ResponseBodyMode.Chunked)
1646-
{
1645+
case ResponseBodyMode.Disabled:
1646+
Output.WriteResponseHeaders(StatusCode, ReasonPhrase, responseHeaders, _responseBodyMode, appCompleted: false);
1647+
HandleNonBodyResponseWrite();
1648+
return Output.FlushAsync(cancellationToken);
1649+
case ResponseBodyMode.Chunked:
16471650
if (data.Length == 0)
16481651
{
16491652
Output.WriteResponseHeaders(StatusCode, ReasonPhrase, responseHeaders, _responseBodyMode, appCompleted: false);
16501653
return Output.FlushAsync(cancellationToken);
16511654
}
16521655

16531656
return Output.FirstWriteChunkedAsync(StatusCode, ReasonPhrase, responseHeaders, _responseBodyMode, data.Span, cancellationToken);
1654-
}
1655-
else
1656-
{
1657+
case ResponseBodyMode.ContentLength:
16571658
CheckLastWrite();
16581659
return Output.FirstWriteAsync(StatusCode, ReasonPhrase, responseHeaders, _responseBodyMode, data.Span, cancellationToken);
1659-
}
1660-
}
1661-
else
1662-
{
1663-
Output.WriteResponseHeaders(StatusCode, ReasonPhrase, responseHeaders, _responseBodyMode, appCompleted: false);
1664-
HandleNonBodyResponseWrite();
1665-
return Output.FlushAsync(cancellationToken);
1660+
case ResponseBodyMode.Uninitialized:
1661+
ThrowInvalidOperation();
1662+
break;
16661663
}
1664+
1665+
Debug.Assert(false, "Should not reach here, all cases in above switch statement should return");
1666+
return default;
16671667
}
16681668

16691669
public Task FlushAsync(CancellationToken cancellationToken = default)
@@ -1689,27 +1689,34 @@ public async ValueTask<FlushResult> WriteAsyncAwaited(Task initializeTask, ReadO
16891689

16901690
// WriteAsyncAwaited is only called for the first write to the body.
16911691
// Ensure headers are flushed if Write(Chunked)Async isn't called.
1692-
if (_responseBodyMode != ResponseBodyMode.Disabled)
1692+
switch (_responseBodyMode)
16931693
{
1694-
if (_responseBodyMode == ResponseBodyMode.Chunked)
1695-
{
1694+
case ResponseBodyMode.Disabled:
1695+
HandleNonBodyResponseWrite();
1696+
return await Output.FlushAsync(cancellationToken);
1697+
case ResponseBodyMode.Chunked:
16961698
if (data.Length == 0)
16971699
{
16981700
return await Output.FlushAsync(cancellationToken);
16991701
}
17001702

17011703
return await Output.WriteChunkAsync(data.Span, cancellationToken);
1702-
}
1703-
else
1704-
{
1704+
case ResponseBodyMode.ContentLength:
17051705
CheckLastWrite();
17061706
return await Output.WriteDataToPipeAsync(data.Span, cancellationToken: cancellationToken);
1707-
}
1708-
}
1709-
else
1710-
{
1711-
HandleNonBodyResponseWrite();
1712-
return await Output.FlushAsync(cancellationToken);
1707+
case ResponseBodyMode.Uninitialized:
1708+
ThrowInvalidOperation();
1709+
break;
17131710
}
1711+
1712+
Debug.Assert(false, "Should not reach here, all cases in above switch statement should return");
1713+
return default;
1714+
}
1715+
1716+
[DoesNotReturn]
1717+
[MethodImpl(MethodImplOptions.NoInlining)]
1718+
static void ThrowInvalidOperation()
1719+
{
1720+
throw new InvalidOperationException();
17141721
}
17151722
}

src/Servers/Kestrel/Core/src/Internal/Http/IHttpOutputProducer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ internal interface IHttpOutputProducer
3232

3333
internal enum ResponseBodyMode
3434
{
35+
Uninitialized,
3536
Disabled,
3637
Chunked,
3738
ContentLength

0 commit comments

Comments
 (0)