From 149aa1e798f808ee5afe80fbd8998007332d1c1f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marie=20P=C3=ADchov=C3=A1?= <11718369+ManickaP@users.noreply.github.com> Date: Fri, 10 Jul 2020 08:52:35 +0200 Subject: [PATCH] Implementations of new HttpContent sync methods. (#38635) --- .../Http/HttpClientHandlerTest.Decompression.cs | 21 ++++++++-- .../System/Net/Http/HttpClientHandlerTestBase.cs | 19 +++++++++ .../ref/System.Net.Http.Json.netcoreapp.cs | 1 + .../src/System/Net/Http/Json/JsonContent.cs | 45 +++++++++++++++++++--- .../System/Net/Http/Json/JsonContent.netcoreapp.cs | 5 ++- .../HttpClientJsonExtensionsTests.cs | 15 ++------ .../HttpContentJsonExtensionsTests.cs | 4 +- .../tests/FunctionalTests/JsonContentTests.cs | 23 +++++++---- .../FunctionalTests/JsonContentTests.netcoreapp.cs | 34 ++++++++++++++++ .../System.Net.Http.Json.Functional.Tests.csproj | 3 ++ .../tests/FunctionalTests/TestClasses.cs | 22 ++++++++--- .../System.Net.Http/ref/System.Net.Http.cs | 4 ++ .../SocketsHttpHandler/DecompressionHandler.cs | 6 +++ .../tests/FunctionalTests/SyncHttpHandlerTest.cs | 6 +++ .../ref/System.Utf8String.Experimental.net5.0.cs | 2 + .../src/System.Utf8String.Experimental.csproj | 3 ++ .../src/System/Net/Http/Utf8StringContent.cs | 4 +- .../Net/Http/Utf8StringContent.netcoreapp.cs | 22 +++++++++++ .../System.Utf8String.Experimental.Tests.csproj | 1 + .../System/Net/Http/Utf8StringContentTests.cs | 2 +- .../Net/Http/Utf8StringContentTests.netcoreapp.cs | 38 ++++++++++++++++++ 21 files changed, 241 insertions(+), 39 deletions(-) create mode 100644 src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.netcoreapp.cs create mode 100644 src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.netcoreapp.cs create mode 100644 src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.netcoreapp.cs diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs index 28091e6..7ffddea 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs @@ -64,6 +64,9 @@ namespace System.Net.Http.Functional.Tests } } + private HttpRequestMessage CreateRequest(HttpMethod method, Uri uri, Version version) => + new HttpRequestMessage(method, uri) { Version = version }; + [Theory] [MemberData(nameof(DecompressedResponse_MethodSpecified_DecompressedContentReturned_MemberData))] public async Task DecompressedResponse_MethodSpecified_DecompressedContentReturned( @@ -162,11 +165,17 @@ namespace System.Net.Http.Functional.Tests [Theory, MemberData(nameof(RemoteServersAndCompressionUris))] public async Task GetAsync_SetAutomaticDecompression_ContentDecompressed(Configuration.Http.RemoteServer remoteServer, Uri uri) { + // Sync API supported only up to HTTP/1.1 + if (!TestAsync && remoteServer.HttpVersion.Major >= 2) + { + return; + } + HttpClientHandler handler = CreateHttpClientHandler(); handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) { - using (HttpResponseMessage response = await client.GetAsync(uri)) + using (HttpResponseMessage response = await client.SendAsync(TestAsync, CreateRequest(HttpMethod.Get, uri, remoteServer.HttpVersion))) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); string responseContent = await response.Content.ReadAsStringAsync(); @@ -184,10 +193,16 @@ namespace System.Net.Http.Functional.Tests [Theory, MemberData(nameof(RemoteServersAndCompressionUris))] public async Task GetAsync_SetAutomaticDecompression_HeadersRemoved(Configuration.Http.RemoteServer remoteServer, Uri uri) { + // Sync API supported only up to HTTP/1.1 + if (!TestAsync && remoteServer.HttpVersion.Major >= 2) + { + return; + } + HttpClientHandler handler = CreateHttpClientHandler(); handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) - using (HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead)) + using (HttpResponseMessage response = await client.SendAsync(TestAsync, CreateRequest(HttpMethod.Get, uri, remoteServer.HttpVersion), HttpCompletionOption.ResponseHeadersRead)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -236,7 +251,7 @@ namespace System.Net.Http.Functional.Tests client.DefaultRequestHeaders.Add("Accept-Encoding", manualAcceptEncodingHeaderValues); } - Task clientTask = client.GetAsync(url); + Task clientTask = client.SendAsync(TestAsync, CreateRequest(HttpMethod.Get, url, UseVersion)); Task> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(); await TaskTimeoutExtensions.WhenAllOrAnyFailed(new Task[] { clientTask, serverTask }); diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs index 79605ba..9d0e62e 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTestBase.cs @@ -109,6 +109,25 @@ namespace System.Net.Http.Functional.Tests _expectedVersion = expectedVersion; } +#if NETCOREAPP + protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) + { + if (request.Version != _expectedVersion) + { + throw new Exception($"Unexpected request version: expected {_expectedVersion}, saw {request.Version}"); + } + + HttpResponseMessage response = base.Send(request, cancellationToken); + + if (response.Version != _expectedVersion) + { + throw new Exception($"Unexpected response version: expected {_expectedVersion}, saw {response.Version}"); + } + + return response; + } +#endif + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (request.Version != _expectedVersion) diff --git a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.netcoreapp.cs b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.netcoreapp.cs index d362d2d..0388fef 100644 --- a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.netcoreapp.cs +++ b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.netcoreapp.cs @@ -12,6 +12,7 @@ namespace System.Net.Http.Json { public sealed partial class JsonContent : System.Net.Http.HttpContent { + protected override void SerializeToStream(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { } protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } } } diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs index 89623cc..3e28569 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs @@ -51,7 +51,7 @@ namespace System.Net.Http.Json => new JsonContent(inputValue, inputType, mediaType, options); protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) - => SerializeToStreamAsyncCore(stream, CancellationToken.None); + => SerializeToStreamAsyncCore(stream, async: true, CancellationToken.None); protected override bool TryComputeLength(out long length) { @@ -59,7 +59,7 @@ namespace System.Net.Http.Json return false; } - private async Task SerializeToStreamAsyncCore(Stream targetStream, CancellationToken cancellationToken) + private async Task SerializeToStreamAsyncCore(Stream targetStream, bool async, CancellationToken cancellationToken) { Encoding? targetEncoding = GetEncoding(Headers.ContentType?.CharSet); @@ -70,15 +70,34 @@ namespace System.Net.Http.Json Stream transcodingStream = Encoding.CreateTranscodingStream(targetStream, targetEncoding, Encoding.UTF8, leaveOpen: true); try { - await JsonSerializer.SerializeAsync(transcodingStream, Value, ObjectType, _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); + if (async) + { + await JsonSerializer.SerializeAsync(transcodingStream, Value, ObjectType, _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); + } + else + { + // Have to use Utf8JsonWriter because JsonSerializer doesn't support sync serialization into stream directly. + // ToDo: Remove Utf8JsonWriter usage after https://github.com/dotnet/runtime/issues/1574 + using var writer = new Utf8JsonWriter(transcodingStream); + JsonSerializer.Serialize(writer, Value, ObjectType, _jsonSerializerOptions); + } } finally { - // DisposeAsync will flush any partial write buffers. In practice our partial write + // Dispose/DisposeAsync will flush any partial write buffers. In practice our partial write // buffers should be empty as we expect JsonSerializer to emit only well-formed UTF-8 data. - await transcodingStream.DisposeAsync().ConfigureAwait(false); + if (async) + { + await transcodingStream.DisposeAsync().ConfigureAwait(false); + } + else + { + transcodingStream.Dispose(); + } } #else + Debug.Assert(async); + using (TranscodingWriteStream transcodingStream = new TranscodingWriteStream(targetStream, targetEncoding)) { await JsonSerializer.SerializeAsync(transcodingStream, Value, ObjectType, _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); @@ -91,7 +110,21 @@ namespace System.Net.Http.Json } else { - await JsonSerializer.SerializeAsync(targetStream, Value, ObjectType, _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); + if (async) + { + await JsonSerializer.SerializeAsync(targetStream, Value, ObjectType, _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); + } + else + { +#if NETCOREAPP + // Have to use Utf8JsonWriter because JsonSerializer doesn't support sync serialization into stream directly. + // ToDo: Remove Utf8JsonWriter usage after https://github.com/dotnet/runtime/issues/1574 + using var writer = new Utf8JsonWriter(targetStream); + JsonSerializer.Serialize(writer, Value, ObjectType, _jsonSerializerOptions); +#else + Debug.Fail("Synchronous serialization is only supported since .NET 5.0"); +#endif + } } } diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.netcoreapp.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.netcoreapp.cs index 306029e..7520cd7 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.netcoreapp.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.netcoreapp.cs @@ -9,7 +9,10 @@ namespace System.Net.Http.Json { public sealed partial class JsonContent { + protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellationToken) + => SerializeToStreamAsyncCore(stream, async: false, cancellationToken).GetAwaiter().GetResult(); + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) - => SerializeToStreamAsyncCore(stream, cancellationToken); + => SerializeToStreamAsyncCore(stream, async: true, cancellationToken); } } diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs index 0bc97ea..7ad9f4c 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Threading.Tasks; @@ -13,17 +13,10 @@ namespace System.Net.Http.Json.Functional.Tests { public class HttpClientJsonExtensionsTests { - private static readonly JsonSerializerOptions s_defaultSerializerOptions - = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - [Fact] public async Task TestGetFromJsonAsync() { - const string json = @"{""Name"":""David"",""Age"":24}"; + string json = Person.Create().Serialize(); HttpHeaderData header = new HttpHeaderData("Content-Type", "application/json"); List headers = new List { header }; @@ -89,7 +82,7 @@ namespace System.Net.Http.Json.Functional.Tests async server => { HttpRequestData request = await server.HandleRequestAsync(); ValidateRequest(request); - Person per = JsonSerializer.Deserialize(request.Body, s_defaultSerializerOptions); + Person per = JsonSerializer.Deserialize(request.Body, JsonOptions.DefaultSerializerOptions); per.Validate(); }); } @@ -121,7 +114,7 @@ namespace System.Net.Http.Json.Functional.Tests async server => { HttpRequestData request = await server.HandleRequestAsync(); ValidateRequest(request); - Person obj = JsonSerializer.Deserialize(request.Body, s_defaultSerializerOptions); + Person obj = JsonSerializer.Deserialize(request.Body, JsonOptions.DefaultSerializerOptions); obj.Validate(); }); } diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs index c0edaba..99d5f1b 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; @@ -154,7 +154,7 @@ namespace System.Net.Http.Json.Functional.Tests [Fact] public async Task TestGetFromJsonAsyncTextPlainUtf16Async() { - const string json = @"{""Name"":""David"",""Age"":24}"; + string json = Person.Create().Serialize(); await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( async (handler, uri) => { diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.cs index 95fcb80..a23a7c8 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.cs @@ -1,8 +1,9 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Net.Http.Headers; using System.Net.Test.Common; +using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; using System.Threading.Tasks; @@ -10,8 +11,9 @@ using Xunit; namespace System.Net.Http.Json.Functional.Tests { - public class JsonContentTests + public abstract class JsonContentTestsBase { + protected abstract Task SendAsync(HttpClient client, HttpRequestMessage request); private class Foo { } private class Bar { } @@ -80,7 +82,7 @@ namespace System.Net.Http.Json.Functional.Tests var request = new HttpRequestMessage(HttpMethod.Post, uri); request.Content = content; - await client.SendAsync(request); + await SendAsync(client, request); } }, async server => { @@ -112,7 +114,7 @@ namespace System.Net.Http.Json.Functional.Tests var request = new HttpRequestMessage(HttpMethod.Post, uri); MediaTypeHeaderValue mediaType = MediaTypeHeaderValue.Parse("foo/bar; charset=utf-8"); request.Content = JsonContent.Create(Person.Create(), mediaType: mediaType); - await client.SendAsync(request); + await SendAsync(client, request); } }, async server => { @@ -159,7 +161,7 @@ namespace System.Net.Http.Json.Functional.Tests } [Fact] - public static async Task ValidateUtf16IsTranscodedAsync() + public async Task ValidateUtf16IsTranscodedAsync() { await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync( async (handler, uri) => @@ -170,7 +172,7 @@ namespace System.Net.Http.Json.Functional.Tests MediaTypeHeaderValue mediaType = MediaTypeHeaderValue.Parse("application/json; charset=utf-16"); // Pass new options to avoid using the Default Web Options that use camelCase. request.Content = JsonContent.Create(Person.Create(), mediaType: mediaType, options: new JsonSerializerOptions()); - await client.SendAsync(request); + await SendAsync(client, request); } }, async server => { @@ -193,7 +195,7 @@ namespace System.Net.Http.Json.Functional.Tests EnsureDefaultOptions dummyObj = new EnsureDefaultOptions(); var request = new HttpRequestMessage(HttpMethod.Post, uri); request.Content = JsonContent.Create(dummyObj); - await client.SendAsync(request); + await SendAsync(client, request); } }, server => server.HandleRequestAsync()); @@ -213,7 +215,7 @@ namespace System.Net.Http.Json.Functional.Tests content.Headers.ContentType = null; request.Content = content; - await client.SendAsync(request); + await SendAsync(client, request); } }, async server => { @@ -222,4 +224,9 @@ namespace System.Net.Http.Json.Functional.Tests }); } } + + public class JsonContentTests_Async : JsonContentTestsBase + { + protected override Task SendAsync(HttpClient client, HttpRequestMessage request) => client.SendAsync(request); + } } diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.netcoreapp.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.netcoreapp.cs new file mode 100644 index 0000000..dcbece5 --- /dev/null +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContentTests.netcoreapp.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Net.Http.Headers; +using System.Net.Test.Common; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Xunit; + +namespace System.Net.Http.Json.Functional.Tests +{ + public class JsonContentTests_Sync : JsonContentTestsBase + { + protected override Task SendAsync(HttpClient client, HttpRequestMessage request) => Task.Run(() => client.Send(request)); + + [Fact] + public void JsonContent_CopyTo_Succeeds() + { + Person person = Person.Create(); + using JsonContent content = JsonContent.Create(person); + using MemoryStream stream = new MemoryStream(); + // HttpContent.CopyTo internally calls overriden JsonContent.SerializeToStream, which is the targeted method of this test. + content.CopyTo(stream, context: null, cancellationToken: default); + stream.Seek(0, SeekOrigin.Begin); + using StreamReader reader = new StreamReader(stream); + string json = reader.ReadToEnd(); + Assert.Equal(person.Serialize(JsonOptions.DefaultSerializerOptions), json); + } + } +} diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj index 8d3e902..2653fcb 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj @@ -8,6 +8,9 @@ + + + diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs index 2318193..2ca9ed4 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs @@ -13,25 +13,37 @@ namespace System.Net.Http.Json.Functional.Tests public int Age { get; set; } public string Name { get; set; } public Person Parent { get; set; } + public string PlaceOfBirth { get; set; } public void Validate() { - Assert.Equal("David", Name); - Assert.Equal(24, Age); + Assert.Equal("R. Daneel Olivaw", Name); + Assert.Equal(19_230, Age); + Assert.Equal("Horní Dolní", PlaceOfBirth); Assert.Null(Parent); } public static Person Create() { - return new Person { Name = "David", Age = 24 }; + return new Person { Name = "R. Daneel Olivaw", Age = 19_230, PlaceOfBirth = "Horní Dolní"}; } - public string Serialize() + public string Serialize(JsonSerializerOptions options = null) { - return JsonSerializer.Serialize(this); + return JsonSerializer.Serialize(this, options); } } + internal static class JsonOptions + { + public static readonly JsonSerializerOptions DefaultSerializerOptions + = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + } + internal class EnsureDefaultOptionsConverter : JsonConverter { public override EnsureDefaultOptions Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index e3d9247..f656514 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -10,6 +10,7 @@ namespace System.Net.Http { public ByteArrayContent(byte[] content) { } public ByteArrayContent(byte[] content, int offset, int count) { } + protected override System.IO.Stream CreateContentReadStream(System.Threading.CancellationToken cancellationToken) { throw null; } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } protected override void SerializeToStream(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { } protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } @@ -251,6 +252,7 @@ namespace System.Net.Http public MultipartContent(string subtype) { } public MultipartContent(string subtype, string boundary) { } public virtual void Add(System.Net.Http.HttpContent content) { } + protected override System.IO.Stream CreateContentReadStream(System.Threading.CancellationToken cancellationToken) { throw null; } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync(System.Threading.CancellationToken cancellationToken) { throw null; } protected override void Dispose(bool disposing) { } @@ -273,6 +275,7 @@ namespace System.Net.Http public sealed partial class ReadOnlyMemoryContent : System.Net.Http.HttpContent { public ReadOnlyMemoryContent(System.ReadOnlyMemory content) { } + protected override System.IO.Stream CreateContentReadStream(System.Threading.CancellationToken cancellationToken) { throw null; } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } protected override void SerializeToStream(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { } protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } @@ -312,6 +315,7 @@ namespace System.Net.Http { public StreamContent(System.IO.Stream content) { } public StreamContent(System.IO.Stream content, int bufferSize) { } + protected override System.IO.Stream CreateContentReadStream(System.Threading.CancellationToken cancellationToken) { throw null; } protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } protected override void Dispose(bool disposing) { } protected override void SerializeToStream(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs index 1380b9c..2fcd31d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs @@ -121,6 +121,12 @@ namespace System.Net.Http protected abstract Stream GetDecompressedStream(Stream originalStream); + protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellationToken) + { + using Stream decompressedStream = CreateContentReadStream(cancellationToken); + decompressedStream.CopyTo(stream); + } + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => SerializeToStreamAsync(stream, context, CancellationToken.None); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs index 8eea9e9..7ecfee6 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SyncHttpHandlerTest.cs @@ -41,6 +41,12 @@ namespace System.Net.Http.Functional.Tests protected override bool TestAsync => false; } + public sealed class SyncHttpHandler_HttpClientHandler_Decompression_Tests : HttpClientHandler_Decompression_Test + { + public SyncHttpHandler_HttpClientHandler_Decompression_Tests(ITestOutputHelper output) : base(output) { } + protected override bool TestAsync => false; + } + public sealed class SyncHttpHandler_IdnaProtocolTests : IdnaProtocolTests { public SyncHttpHandler_IdnaProtocolTests(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs index fdccb75..85f2598 100644 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs +++ b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs @@ -19,6 +19,8 @@ namespace System.Net.Http { public sealed partial class Utf8StringContent : System.Net.Http.HttpContent { + protected override System.IO.Stream CreateContentReadStream(System.Threading.CancellationToken cancellationToken) { throw null; } + protected override void SerializeToStream(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { } protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } } } diff --git a/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj b/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj index 3c93df3..4496422 100644 --- a/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj +++ b/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj @@ -107,6 +107,9 @@ + + + diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.cs b/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.cs index a6e3452..3efd25f 100644 --- a/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.cs +++ b/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; namespace System.Net.Http { - public sealed class Utf8StringContent : HttpContent + public sealed partial class Utf8StringContent : HttpContent { private const string DefaultMediaType = "text/plain"; @@ -42,7 +42,7 @@ namespace System.Net.Http Task.FromResult(new Utf8StringStream(_content)); #if NETSTANDARD2_0 - protected async override Task SerializeToStreamAsync(Stream stream, TransportContext? context) + protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context) { ReadOnlyMemory buffer = _content.AsMemoryBytes(); if (MemoryMarshal.TryGetArray(buffer, out ArraySegment array)) diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.netcoreapp.cs new file mode 100644 index 0000000..d8a7b51 --- /dev/null +++ b/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.netcoreapp.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.IO; +using System.Net.Http.Headers; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Net.Http +{ + public sealed partial class Utf8StringContent + { + protected override Stream CreateContentReadStream(CancellationToken cancellationToken) => + new Utf8StringStream(_content); + + protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellationToken) => + stream.Write(_content.AsBytes()); + } +} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj b/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj index 73e5276..1edb4b7 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj +++ b/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj @@ -37,6 +37,7 @@ + diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.cs index eedac58..9ea0a4c 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.cs +++ b/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.cs @@ -32,7 +32,7 @@ namespace System.Net.Http.Tests } [Fact] - public static async Task Ctor_GetStream() + public static async Task Ctor_CopyToAsync_GetStream() { MemoryStream memoryStream = new MemoryStream(); diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.netcoreapp.cs new file mode 100644 index 0000000..8df8b1e --- /dev/null +++ b/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.netcoreapp.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +using static System.Tests.Utf8TestUtilities; + +namespace System.Net.Http.Tests +{ + public partial class Utf8StringContentTests + { + [Fact] + public static void Ctor_CopyTo_GetStream() + { + var memoryStream = new MemoryStream(); + + new Utf8StringContent(u8("Hello")).CopyTo(memoryStream, default, default); + + Assert.Equal(u8("Hello").ToByteArray(), memoryStream.ToArray()); + } + + [Fact] + public static void Ctor_ReadAsStream() + { + var content = new Utf8StringContent(u8("Hello")); + Stream stream = content.ReadAsStream(); + + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + Assert.Equal(u8("Hello").ToByteArray(), memoryStream.ToArray()); + } + } +} -- 2.7.4