Skip to content

Commit bc4cca2

Browse files
stephentoubangelobreuerManickaP
authored
Fix inconsistency of the 'CanRead' property after disposing an HTTP content stream (#43766)
* Fix inconsistency of the 'CanRead' property after disposing an HTTP content stream * Update src/libraries/System.Net.Http/tests/FunctionalTests/RawConnectionStreamTest.cs Co-authored-by: Marie Píchová <[email protected]> Co-authored-by: Angelo Breuer <[email protected]> Co-authored-by: Marie Píchová <[email protected]>
1 parent eec1e25 commit bc4cca2

File tree

8 files changed

+73
-8
lines changed

8 files changed

+73
-8
lines changed

src/libraries/Common/tests/System/Net/Http/ResponseStreamTest.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,29 @@ await StartTransferTypeAndErrorServer(transferType, transferError, async uri =>
254254
await ReadAsStreamHelper(uri);
255255
});
256256
}
257+
258+
[Theory]
259+
[InlineData(TransferType.None, TransferError.None)]
260+
[InlineData(TransferType.ContentLength, TransferError.None)]
261+
[InlineData(TransferType.Chunked, TransferError.None)]
262+
public async Task ReadAsStreamAsync_StreamCanReadIsFalseAfterDispose(
263+
TransferType transferType,
264+
TransferError transferError)
265+
{
266+
await StartTransferTypeAndErrorServer(transferType, transferError, async uri =>
267+
{
268+
using (HttpClient client = CreateHttpClient())
269+
using (HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead))
270+
{
271+
Stream stream = await response.Content.ReadAsStreamAsync();
272+
Assert.True(stream.CanRead);
273+
274+
stream.Dispose();
275+
276+
Assert.False(stream.CanRead);
277+
}
278+
});
279+
}
257280
#endif
258281

259282
public enum TransferType

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,7 +1415,7 @@ protected override void Dispose(bool disposing)
14151415
base.Dispose(disposing);
14161416
}
14171417

1418-
public override bool CanRead => true;
1418+
public override bool CanRead => _http2Stream != null;
14191419
public override bool CanWrite => false;
14201420

14211421
public override int Read(Span<byte> destination)
@@ -1488,7 +1488,7 @@ protected override void Dispose(bool disposing)
14881488
}
14891489

14901490
public override bool CanRead => false;
1491-
public override bool CanWrite => true;
1491+
public override bool CanWrite => _http2Stream != null;
14921492

14931493
public override int Read(Span<byte> buffer) => throw new NotSupportedException();
14941494

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,7 @@ private sealed class Http3ReadStream : HttpBaseStream
11711171
private Http3RequestStream? _stream;
11721172
private HttpResponseMessage? _response;
11731173

1174-
public override bool CanRead => true;
1174+
public override bool CanRead => _stream != null;
11751175

11761176
public override bool CanWrite => false;
11771177

@@ -1256,7 +1256,7 @@ private sealed class Http3WriteStream : HttpBaseStream
12561256

12571257
public override bool CanRead => false;
12581258

1259-
public override bool CanWrite => true;
1259+
public override bool CanWrite => _stream != null;
12601260

12611261
public Http3WriteStream(Http3RequestStream stream)
12621262
{

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public HttpContentReadStream(HttpConnection connection) : base(connection)
1717
{
1818
}
1919

20-
public sealed override bool CanRead => true;
20+
public sealed override bool CanRead => _disposed == 0;
2121
public sealed override bool CanWrite => false;
2222

2323
public sealed override void Write(ReadOnlySpan<byte> buffer) => throw new NotSupportedException(SR.net_http_content_readonly_stream);

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public HttpContentWriteStream(HttpConnection connection) : base(connection) =>
1818
Debug.Assert(connection != null);
1919

2020
public sealed override bool CanRead => false;
21-
public sealed override bool CanWrite => true;
21+
public sealed override bool CanWrite => _connection != null;
2222

2323
public sealed override void Flush() =>
2424
_connection?.Flush();

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ public RawConnectionStream(HttpConnection connection) : base(connection)
1717
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this);
1818
}
1919

20-
public sealed override bool CanRead => true;
21-
public sealed override bool CanWrite => true;
20+
public sealed override bool CanRead => _connection != null;
21+
public sealed override bool CanWrite => _connection != null;
2222

2323
public override int Read(Span<byte> buffer)
2424
{
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.IO;
5+
using System.Net.Test.Common;
6+
using System.Threading.Tasks;
7+
8+
using Xunit;
9+
10+
namespace System.Net.Http.Functional.Tests
11+
{
12+
public class RawConnectionStreamTest
13+
{
14+
[Fact]
15+
public async Task RawConnectionStream_Dispose()
16+
{
17+
await LoopbackServer.CreateClientAndServerAsync(async url =>
18+
{
19+
using (HttpClient client = new HttpClient())
20+
{
21+
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
22+
HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
23+
Stream responseStream = await response.Content.ReadAsStreamAsync();
24+
25+
Assert.True(responseStream.CanRead);
26+
Assert.True(responseStream.CanWrite);
27+
28+
responseStream.Dispose();
29+
30+
Assert.False(responseStream.CanRead);
31+
Assert.False(responseStream.CanWrite);
32+
}
33+
},
34+
async server =>
35+
{
36+
// --> used to return System.Net.Http.HttpConnection+RawConnectionStream
37+
await server.HandleRequestAsync(HttpStatusCode.SwitchingProtocols);
38+
});
39+
}
40+
}
41+
}

src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
<Compile Include="TelemetryTest.cs" />
156156
<Compile Include="StreamContentTest.cs" />
157157
<Compile Include="StringContentTest.cs" />
158+
<Compile Include="RawConnectionStreamTest.cs" />
158159
<Compile Include="$(CommonTestPath)System\Net\Http\SyncBlockingContent.cs"
159160
Link="Common\System\Net\Http\SyncBlockingContent.cs" />
160161
<Compile Include="$(CommonTestPath)System\Net\Http\DefaultCredentialsTest.cs"

0 commit comments

Comments
 (0)