Skip to content

Commit 5fd53d9

Browse files
authored
Check HasStarted before calling Flush/Start in StartAsync (#8041)
1 parent 3509323 commit 5fd53d9

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

src/Http/Http/src/Internal/DefaultHttpResponse.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ public override void Redirect(string location, bool permanent)
151151

152152
public override Task StartAsync(CancellationToken cancellationToken = default)
153153
{
154+
if (HasStarted)
155+
{
156+
return Task.CompletedTask;
157+
}
158+
154159
if (HttpResponseStartFeature == null)
155160
{
156161
return HttpResponseFeature.Body.FlushAsync(cancellationToken);

src/Http/Http/test/Internal/DefaultHttpResponseTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ public async Task ResponseStart_CallsFeatureIfSet()
110110
mock.Setup(o => o.StartAsync(It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
111111
features.Set(mock.Object);
112112

113+
var responseMock = new Mock<IHttpResponseFeature>();
114+
responseMock.Setup(o => o.HasStarted).Returns(false);
115+
features.Set(responseMock.Object);
116+
113117
var context = new DefaultHttpContext(features);
114118
await context.Response.StartAsync();
115119

@@ -126,12 +130,35 @@ public async Task ResponseStart_CallsFeatureIfSetWithProvidedCancellationToken()
126130
mock.Setup(o => o.StartAsync(It.Is<CancellationToken>((localCt) => localCt.Equals(ct)))).Returns(Task.CompletedTask);
127131
features.Set(mock.Object);
128132

133+
var responseMock = new Mock<IHttpResponseFeature>();
134+
responseMock.Setup(o => o.HasStarted).Returns(false);
135+
features.Set(responseMock.Object);
136+
129137
var context = new DefaultHttpContext(features);
130138
await context.Response.StartAsync(ct);
131139

132140
mock.Verify(m => m.StartAsync(default), Times.Once());
133141
}
134142

143+
[Fact]
144+
public async Task ResponseStart_DoesNotCallStartIfHasStartedIsTrue()
145+
{
146+
var features = new FeatureCollection();
147+
148+
var startMock = new Mock<IHttpResponseStartFeature>();
149+
startMock.Setup(o => o.StartAsync(It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);
150+
features.Set(startMock.Object);
151+
152+
var responseMock = new Mock<IHttpResponseFeature>();
153+
responseMock.Setup(o => o.HasStarted).Returns(true);
154+
features.Set(responseMock.Object);
155+
156+
var context = new DefaultHttpContext(features);
157+
await context.Response.StartAsync();
158+
159+
startMock.Verify(m => m.StartAsync(default), Times.Never());
160+
}
161+
135162
[Fact]
136163
public async Task ResponseStart_CallsResponseBodyFlushIfNotSet()
137164
{

0 commit comments

Comments
 (0)