Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public static partial class HttpClientJsonExtensions
private static Uri? CreateUri(string? uri) =>
string.IsNullOrEmpty(uri) ? null : new Uri(uri, UriKind.RelativeOrAbsolute);

private static async Task<Stream> GetHttpResponseStreamAsync(
private static ValueTask<Stream> GetHttpResponseStreamAsync(
HttpClient client,
HttpResponseMessage response,
bool usingResponseHeadersRead,
Expand All @@ -126,16 +126,17 @@ private static async Task<Stream> GetHttpResponseStreamAsync(
LengthLimitReadStream.ThrowExceededBufferLimit(contentLengthLimit);
}

Stream contentStream = await HttpContentJsonExtensions.GetContentStreamAsync(response.Content, cancellationToken)
.ConfigureAwait(false);
ValueTask<Stream> task = HttpContentJsonExtensions.GetContentStreamAsync(response.Content, cancellationToken);

// If ResponseHeadersRead wasn't used, HttpClient will have already buffered the whole response upfront.
// No need to check the limit again.
Stream readStream = usingResponseHeadersRead
? new LengthLimitReadStream(contentStream, (int)client.MaxResponseContentBufferSize)
: contentStream;
return usingResponseHeadersRead ? GetLengthLimitReadStreamAsync(client, task) : task;
}

return readStream;
private static async ValueTask<Stream> GetLengthLimitReadStreamAsync(HttpClient client, ValueTask<Stream> task)
{
Stream contentStream = await task.ConfigureAwait(false);
return new LengthLimitReadStream(contentStream, (int)client.MaxResponseContentBufferSize);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,21 @@ public static partial class HttpContentJsonExtensions
}
}

internal static async ValueTask<Stream> GetContentStreamAsync(HttpContent content, CancellationToken cancellationToken)
internal static ValueTask<Stream> GetContentStreamAsync(HttpContent content, CancellationToken cancellationToken)
{
Stream contentStream = await ReadHttpContentStreamAsync(content, cancellationToken).ConfigureAwait(false);
Task<Stream> task = ReadHttpContentStreamAsync(content, cancellationToken);

// Wrap content stream into a transcoding stream that buffers the data transcoded from the sourceEncoding to utf-8.
if (JsonHelpers.GetEncoding(content) is Encoding sourceEncoding && sourceEncoding != Encoding.UTF8)
{
contentStream = GetTranscodingStream(contentStream, sourceEncoding);
}
return JsonHelpers.GetEncoding(content) is Encoding sourceEncoding && sourceEncoding != Encoding.UTF8
? GetTranscodingStreamAsync(task, sourceEncoding)
: new(task);
}

return contentStream;
private static async ValueTask<Stream> GetTranscodingStreamAsync(Task<Stream> task, Encoding sourceEncoding)
{
Stream contentStream = await task.ConfigureAwait(false);

// Wrap content stream into a transcoding stream that buffers the data transcoded from the sourceEncoding to utf-8.
return GetTranscodingStream(contentStream, sourceEncoding);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,75 +94,64 @@ public static JsonContent Create(object? inputValue, JsonTypeInfo jsonTypeInfo,
}

protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context)
=> SerializeToStreamAsyncCore(stream, async: true, CancellationToken.None);
=> SerializeToStreamAsyncCore(stream, CancellationToken.None);

protected override bool TryComputeLength(out long length)
{
length = 0;
return false;
}

private async Task SerializeToStreamAsyncCore(Stream targetStream, bool async, CancellationToken cancellationToken)
private Task SerializeToStreamAsyncCore(Stream targetStream, CancellationToken cancellationToken)
{
Encoding? targetEncoding = JsonHelpers.GetEncoding(this);

return targetEncoding != null && targetEncoding != Encoding.UTF8
? SerializeToStreamAsyncTranscoding(targetStream, async: true, targetEncoding, cancellationToken)
: JsonSerializer.SerializeAsync(targetStream, Value, _typeInfo, cancellationToken);
}

private async Task SerializeToStreamAsyncTranscoding(Stream targetStream, bool async, Encoding targetEncoding, CancellationToken cancellationToken)
{
// Wrap provided stream into a transcoding stream that buffers the data transcoded from utf-8 to the targetEncoding.
if (targetEncoding != null && targetEncoding != Encoding.UTF8)
{
#if NETCOREAPP
Stream transcodingStream = Encoding.CreateTranscodingStream(targetStream, targetEncoding, Encoding.UTF8, leaveOpen: true);
try
{
if (async)
{
await JsonSerializer.SerializeAsync(transcodingStream, Value, _typeInfo, cancellationToken).ConfigureAwait(false);
}
else
{
JsonSerializer.Serialize(transcodingStream, Value, _typeInfo);
}
}
finally
Stream transcodingStream = Encoding.CreateTranscodingStream(targetStream, targetEncoding, Encoding.UTF8, leaveOpen: true);
try
{
if (async)
{
// 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.
if (async)
{
await transcodingStream.DisposeAsync().ConfigureAwait(false);
}
else
{
transcodingStream.Dispose();
}
await JsonSerializer.SerializeAsync(transcodingStream, Value, _typeInfo, cancellationToken).ConfigureAwait(false);
}
#else
Debug.Assert(async, "HttpContent synchronous serialization is only supported since .NET 5.0");

using (TranscodingWriteStream transcodingStream = new TranscodingWriteStream(targetStream, targetEncoding))
else
{
await JsonSerializer.SerializeAsync(transcodingStream, Value, _typeInfo, cancellationToken).ConfigureAwait(false);
// The transcoding streams use Encoders and Decoders that have internal buffers. We need to flush these
// when there is no more data to be written. Stream.FlushAsync isn't suitable since it's
// acceptable to Flush a Stream (multiple times) prior to completion.
await transcodingStream.FinalWriteAsync(cancellationToken).ConfigureAwait(false);
JsonSerializer.Serialize(transcodingStream, Value, _typeInfo);
}
#endif
}
else
finally
{
// 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.
if (async)
{
await JsonSerializer.SerializeAsync(targetStream, Value, _typeInfo, cancellationToken).ConfigureAwait(false);
await transcodingStream.DisposeAsync().ConfigureAwait(false);
}
else
{
#if NETCOREAPP
JsonSerializer.Serialize(targetStream, Value, _typeInfo);
#else
Debug.Fail("HttpContent synchronous serialization is only supported since .NET 5.0");
#endif
transcodingStream.Dispose();
}
}
#else
Debug.Assert(async, "HttpContent synchronous serialization is only supported since .NET 5.0");

using (TranscodingWriteStream transcodingStream = new TranscodingWriteStream(targetStream, targetEncoding))
{
await JsonSerializer.SerializeAsync(transcodingStream, Value, _typeInfo, cancellationToken).ConfigureAwait(false);
// The transcoding streams use Encoders and Decoders that have internal buffers. We need to flush these
// when there is no more data to be written. Stream.FlushAsync isn't suitable since it's
// acceptable to Flush a Stream (multiple times) prior to completion.
await transcodingStream.FinalWriteAsync(cancellationToken).ConfigureAwait(false);
}
#endif
}

private static void EnsureTypeCompatibility(object? inputValue, Type inputType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -10,9 +12,18 @@ 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();
{
if (JsonHelpers.GetEncoding(this) is Encoding targetEncoding && targetEncoding != Encoding.UTF8)
{
SerializeToStreamAsyncTranscoding(stream, async: false, targetEncoding, cancellationToken).GetAwaiter().GetResult();
}
else
{
JsonSerializer.Serialize(stream, Value, _typeInfo);
}
}

protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken)
=> SerializeToStreamAsyncCore(stream, async: true, cancellationToken);
=> SerializeToStreamAsyncCore(stream, cancellationToken);
}
}