From 0b2387b4ff27cda60ccf778c30f882ae74fd3783 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 23 Jun 2021 13:47:19 +0200 Subject: [PATCH 1/3] browser http response stream could be seekable --- .../System/Net/Http/HttpClientHandlerTest.cs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 33392864210a83..993b20947de00c 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -936,7 +936,6 @@ await connection.WriteStringAsync( [InlineData(true)] [InlineData(false)] [InlineData(null)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/54159", TestPlatforms.Browser)] public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(bool? chunked) { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -969,21 +968,24 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => // Boolean properties returning correct values Assert.True(responseStream.CanRead); Assert.False(responseStream.CanWrite); - Assert.False(responseStream.CanSeek); + Assert.Equal(PlatformDetection.IsBrowser, responseStream.CanSeek); // Not supported operations Assert.Throws(() => responseStream.BeginWrite(new byte[1], 0, 1, null, null)); - Assert.Throws(() => responseStream.Length); - Assert.Throws(() => responseStream.Position); - Assert.Throws(() => responseStream.Position = 0); - Assert.Throws(() => responseStream.Seek(0, SeekOrigin.Begin)); + if (PlatformDetection.IsNotBrowser) + { + Assert.Throws(() => responseStream.Length); + Assert.Throws(() => responseStream.Position); + Assert.Throws(() => responseStream.Position = 0); + Assert.Throws(() => responseStream.Seek(0, SeekOrigin.Begin)); + } Assert.Throws(() => responseStream.SetLength(0)); Assert.Throws(() => responseStream.Write(new byte[1], 0, 1)); #if !NETFRAMEWORK Assert.Throws(() => responseStream.Write(new Span(new byte[1]))); - Assert.Throws(() => { responseStream.WriteAsync(new Memory(new byte[1])); }); + await Assert.ThrowsAsync(async () => await responseStream.WriteAsync(new Memory(new byte[1]))); #endif - Assert.Throws(() => { responseStream.WriteAsync(new byte[1], 0, 1); }); + await Assert.ThrowsAsync(async () => await responseStream.WriteAsync(new byte[1], 0, 1)); Assert.Throws(() => responseStream.WriteByte(1)); // Invalid arguments @@ -1102,7 +1104,6 @@ await server.AcceptConnectionAsync(async connection => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/54159", TestPlatforms.Browser)] public async Task ReadAsStreamAsync_EmptyResponseBody_HandlerProducesWellBehavedResponseStream() { if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) @@ -1122,14 +1123,17 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => // Boolean properties returning correct values Assert.True(responseStream.CanRead); Assert.False(responseStream.CanWrite); - Assert.False(responseStream.CanSeek); + Assert.Equal(PlatformDetection.IsBrowser, responseStream.CanSeek); // Not supported operations Assert.Throws(() => responseStream.BeginWrite(new byte[1], 0, 1, null, null)); - Assert.Throws(() => responseStream.Length); - Assert.Throws(() => responseStream.Position); - Assert.Throws(() => responseStream.Position = 0); - Assert.Throws(() => responseStream.Seek(0, SeekOrigin.Begin)); + if (PlatformDetection.IsNotBrowser) + { + Assert.Throws(() => responseStream.Length); + Assert.Throws(() => responseStream.Position); + Assert.Throws(() => responseStream.Position = 0); + Assert.Throws(() => responseStream.Seek(0, SeekOrigin.Begin)); + } Assert.Throws(() => responseStream.SetLength(0)); Assert.Throws(() => responseStream.Write(new byte[1], 0, 1)); #if !NETFRAMEWORK From 3beff75523f2efb0d6405bee37c77bb0044c471c Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 24 Jun 2021 22:25:25 +0200 Subject: [PATCH 2/3] feedback --- .../Common/tests/System/Net/Http/HttpClientHandlerTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 993b20947de00c..2012cf7f7c8328 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -972,7 +972,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => // Not supported operations Assert.Throws(() => responseStream.BeginWrite(new byte[1], 0, 1, null, null)); - if (PlatformDetection.IsNotBrowser) + if (!responseStream.CanSeek) { Assert.Throws(() => responseStream.Length); Assert.Throws(() => responseStream.Position); @@ -1127,7 +1127,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => // Not supported operations Assert.Throws(() => responseStream.BeginWrite(new byte[1], 0, 1, null, null)); - if (PlatformDetection.IsNotBrowser) + if (!responseStream.CanSeek) { Assert.Throws(() => responseStream.Length); Assert.Throws(() => responseStream.Position); From 8643c54a14aa4d947349182b3d3383b6e3d5eb72 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 24 Jun 2021 22:51:43 +0200 Subject: [PATCH 3/3] test WebAssemblyEnableStreamingResponse --- .../System/Net/Http/HttpClientHandlerTest.cs | 127 ++++++++++++------ 1 file changed, 85 insertions(+), 42 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index 2012cf7f7c8328..eab9aaa44ac396 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -958,6 +958,11 @@ public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(boo await LoopbackServerFactory.CreateClientAndServerAsync(async uri => { var request = new HttpRequestMessage(HttpMethod.Get, uri) { Version = UseVersion }; + if (PlatformDetection.IsBrowser) + { + request.Options.Set(new HttpRequestOptionsKey("WebAssemblyEnableStreamingResponse"), true); + } + using (var client = new HttpMessageInvoker(CreateHttpClientHandler())) using (HttpResponseMessage response = await client.SendAsync(TestAsync, request, CancellationToken.None)) { @@ -968,7 +973,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => // Boolean properties returning correct values Assert.True(responseStream.CanRead); Assert.False(responseStream.CanWrite); - Assert.Equal(PlatformDetection.IsBrowser, responseStream.CanSeek); + Assert.False(responseStream.CanSeek); // Not supported operations Assert.Throws(() => responseStream.BeginWrite(new byte[1], 0, 1, null, null)); @@ -999,11 +1004,14 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.Throws(() => { responseStream.CopyToAsync(Stream.Null, -1, default); }); Assert.Throws(() => { responseStream.CopyToAsync(nonWritableStream, 100, default); }); Assert.Throws(() => { responseStream.CopyToAsync(disposedStream, 100, default); }); - Assert.Throws(() => responseStream.Read(null, 0, 100)); - Assert.Throws(() => responseStream.Read(new byte[1], -1, 1)); - Assert.ThrowsAny(() => responseStream.Read(new byte[1], 2, 1)); - Assert.Throws(() => responseStream.Read(new byte[1], 0, -1)); - Assert.ThrowsAny(() => responseStream.Read(new byte[1], 0, 2)); + if (PlatformDetection.IsNotBrowser) + { + Assert.Throws(() => responseStream.Read(null, 0, 100)); + Assert.Throws(() => responseStream.Read(new byte[1], -1, 1)); + Assert.ThrowsAny(() => responseStream.Read(new byte[1], 2, 1)); + Assert.Throws(() => responseStream.Read(new byte[1], 0, -1)); + Assert.ThrowsAny(() => responseStream.Read(new byte[1], 0, 2)); + } Assert.Throws(() => responseStream.BeginRead(null, 0, 100, null, null)); Assert.Throws(() => responseStream.BeginRead(new byte[1], -1, 1, null, null)); Assert.ThrowsAny(() => responseStream.BeginRead(new byte[1], 2, 1, null, null)); @@ -1019,62 +1027,97 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => // Various forms of reading var buffer = new byte[1]; - Assert.Equal('h', responseStream.ReadByte()); + if (PlatformDetection.IsBrowser) + { + Assert.Equal('h', await responseStream.ReadByteAsync()); + Assert.Equal('e', await responseStream.ReadByteAsync()); + Assert.Equal(1, await responseStream.ReadAsync(new Memory(buffer))); + Assert.Equal((byte)'l', buffer[0]); + + Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); + Assert.Equal((byte)'l', buffer[0]); + + Assert.Equal(1, await responseStream.ReadAsync(buffer)); + Assert.Equal((byte)'o', buffer[0]); + + Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); + Assert.Equal((byte)' ', buffer[0]); + + // Doing any of these 0-byte reads causes the connection to fail. + Assert.Equal(0, await responseStream.ReadAsync(Memory.Empty)); + Assert.Equal(0, await responseStream.ReadAsync(Array.Empty(), 0, 0)); + + // And copying + var ms = new MemoryStream(); + await responseStream.CopyToAsync(ms); + Assert.Equal("world", Encoding.ASCII.GetString(ms.ToArray())); + + // Read and copy again once we've exhausted all data + ms = new MemoryStream(); + await responseStream.CopyToAsync(ms); + Assert.Equal(0, ms.Length); + Assert.Equal(0, await responseStream.ReadAsync(buffer, 0, 1)); + Assert.Equal(0, await responseStream.ReadAsync(new Memory(buffer))); + } + else + { + Assert.Equal('h', responseStream.ReadByte()); + Assert.Equal(1, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null)); + Assert.Equal((byte)'e', buffer[0]); - Assert.Equal(1, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null)); - Assert.Equal((byte)'e', buffer[0]); #if !NETFRAMEWORK - Assert.Equal(1, await responseStream.ReadAsync(new Memory(buffer))); + Assert.Equal(1, await responseStream.ReadAsync(new Memory(buffer))); #else - Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); + Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); #endif - Assert.Equal((byte)'l', buffer[0]); + Assert.Equal((byte)'l', buffer[0]); - Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); - Assert.Equal((byte)'l', buffer[0]); + Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); + Assert.Equal((byte)'l', buffer[0]); #if !NETFRAMEWORK - Assert.Equal(1, responseStream.Read(new Span(buffer))); + Assert.Equal(1, responseStream.Read(new Span(buffer))); #else - Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); + Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1)); #endif - Assert.Equal((byte)'o', buffer[0]); + Assert.Equal((byte)'o', buffer[0]); - Assert.Equal(1, responseStream.Read(buffer, 0, 1)); - Assert.Equal((byte)' ', buffer[0]); + Assert.Equal(1, responseStream.Read(buffer, 0, 1)); + Assert.Equal((byte)' ', buffer[0]); - // Doing any of these 0-byte reads causes the connection to fail. - Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, Array.Empty(), 0, 0, null)); + // Doing any of these 0-byte reads causes the connection to fail. + Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, Array.Empty(), 0, 0, null)); #if !NETFRAMEWORK - Assert.Equal(0, await responseStream.ReadAsync(Memory.Empty)); + Assert.Equal(0, await responseStream.ReadAsync(Memory.Empty)); #endif - Assert.Equal(0, await responseStream.ReadAsync(Array.Empty(), 0, 0)); + Assert.Equal(0, await responseStream.ReadAsync(Array.Empty(), 0, 0)); #if !NETFRAMEWORK - Assert.Equal(0, responseStream.Read(Span.Empty)); + Assert.Equal(0, responseStream.Read(Span.Empty)); #endif - Assert.Equal(0, responseStream.Read(Array.Empty(), 0, 0)); - - // And copying - var ms = new MemoryStream(); - await responseStream.CopyToAsync(ms); - Assert.Equal("world", Encoding.ASCII.GetString(ms.ToArray())); - - // Read and copy again once we've exhausted all data - ms = new MemoryStream(); - await responseStream.CopyToAsync(ms); - responseStream.CopyTo(ms); - Assert.Equal(0, ms.Length); - Assert.Equal(-1, responseStream.ReadByte()); - Assert.Equal(0, responseStream.Read(buffer, 0, 1)); + Assert.Equal(0, responseStream.Read(Array.Empty(), 0, 0)); + + // And copying + var ms = new MemoryStream(); + await responseStream.CopyToAsync(ms); + Assert.Equal("world", Encoding.ASCII.GetString(ms.ToArray())); + + // Read and copy again once we've exhausted all data + ms = new MemoryStream(); + await responseStream.CopyToAsync(ms); + responseStream.CopyTo(ms); + Assert.Equal(0, ms.Length); + Assert.Equal(-1, responseStream.ReadByte()); + Assert.Equal(0, responseStream.Read(buffer, 0, 1)); #if !NETFRAMEWORK - Assert.Equal(0, responseStream.Read(new Span(buffer))); + Assert.Equal(0, responseStream.Read(new Span(buffer))); #endif - Assert.Equal(0, await responseStream.ReadAsync(buffer, 0, 1)); + Assert.Equal(0, await responseStream.ReadAsync(buffer, 0, 1)); #if !NETFRAMEWORK - Assert.Equal(0, await responseStream.ReadAsync(new Memory(buffer))); + Assert.Equal(0, await responseStream.ReadAsync(new Memory(buffer))); #endif - Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null)); + Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null)); + } } } }, async server =>