Skip to content
85 changes: 74 additions & 11 deletions sdk/core/Azure.Core/src/RequestContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public abstract class RequestContent : IDisposable
/// <param name="content">The <see cref="string"/> to use.</param>
/// <returns>An instance of <see cref="RequestContent"/> that wraps a <see cref="string"/>.</returns>
/// <remarks>The returned content represents the UTF-8 Encoding of the given string.</remarks>
public static RequestContent Create(string content) => Create(s_UTF8NoBomEncoding.GetBytes(content));
public static RequestContent Create(string content) => new CustomStringContent(content, s_UTF8NoBomEncoding);

/// <summary>
/// Creates an instance of <see cref="RequestContent"/> that wraps a <see cref="BinaryData"/>.
Expand Down Expand Up @@ -221,13 +221,8 @@ public override void WriteTo(Stream stream, CancellationToken cancellationToken)

public override bool TryComputeLength(out long length)
{
if (_stream.CanSeek)
{
length = _stream.Length - _origin;
return true;
}
length = 0;
return false;
length = _stream.Length - _origin;
return true;
}

public override async Task WriteToAsync(Stream stream, CancellationToken cancellation)
Expand Down Expand Up @@ -261,7 +256,11 @@ public override void Dispose() { }

public override void WriteTo(Stream stream, CancellationToken cancellation)
{
#if NET6_0_OR_GREATER
stream.Write(_bytes.AsSpan(_contentStart, _contentLength));
#else
stream.Write(_bytes, _contentStart, _contentLength);
#endif
}

public override bool TryComputeLength(out long length)
Expand All @@ -272,9 +271,11 @@ public override bool TryComputeLength(out long length)

public override async Task WriteToAsync(Stream stream, CancellationToken cancellation)
{
#pragma warning disable CA1835 // WriteAsync(Memory<>) overload is not available in all targets
#if NET6_0_OR_GREATER
await stream.WriteAsync(_bytes.AsMemory(_contentStart, _contentLength), cancellation).ConfigureAwait(false);
#else
await stream.WriteAsync(_bytes, _contentStart, _contentLength, cancellation).ConfigureAwait(false);
#pragma warning restore // WriteAsync(Memory<>) overload is not available in all targets
#endif
}
}

Expand All @@ -289,8 +290,13 @@ public override void Dispose() { }

public override void WriteTo(Stream stream, CancellationToken cancellation)
{
#if NET6_0_OR_GREATER
stream.Write(_bytes.Span);
#else

byte[] buffer = _bytes.ToArray();
stream.Write(buffer, 0, buffer.Length);
#endif
}

public override bool TryComputeLength(out long length)
Expand All @@ -316,8 +322,15 @@ public override void Dispose() { }

public override void WriteTo(Stream stream, CancellationToken cancellation)
{
#if NET6_0_OR_GREATER
foreach (var memory in _bytes)
{
stream.Write(memory.Span);
}
#else
byte[] buffer = _bytes.ToArray();
stream.Write(buffer, 0, buffer.Length);
#endif
}

public override bool TryComputeLength(out long length)
Expand All @@ -332,6 +345,56 @@ public override async Task WriteToAsync(Stream stream, CancellationToken cancell
}
}

private sealed class CustomStringContent : RequestContent
{
private readonly byte[] _buffer;
private readonly int _actualByteCount;

public CustomStringContent(string value, Encoding? encoding = null)
{
encoding ??= Encoding.UTF8;
#if NET6_0_OR_GREATER
var byteCount = encoding.GetMaxByteCount(value.Length);
_buffer = ArrayPool<byte>.Shared.Rent(byteCount);
_actualByteCount = encoding.GetBytes(value, _buffer);
#else
_buffer = encoding.GetBytes(value);
_actualByteCount = _buffer.Length;
#endif
}

public override async Task WriteToAsync(Stream stream, CancellationToken cancellation)
{
#if NET6_0_OR_GREATER
await stream.WriteAsync(_buffer.AsMemory(0, _actualByteCount), cancellation).ConfigureAwait(false);
#else
await stream.WriteAsync(_buffer, 0, _actualByteCount, cancellation).ConfigureAwait(false);
#endif
}

public override void WriteTo(Stream stream, CancellationToken cancellation)
{
#if NET6_0_OR_GREATER
stream.Write(_buffer.AsSpan(0, _actualByteCount));
#else
stream.Write(_buffer, 0, _actualByteCount);
#endif
}

public override bool TryComputeLength(out long length)
{
length = _actualByteCount;
return true;
}

public override void Dispose()
{
#if NET6_0_OR_GREATER
ArrayPool<byte>.Shared.Return(_buffer, clearArray: true);
#endif
}
}

private sealed class DynamicDataContent : RequestContent
{
private readonly DynamicData _data;
Expand All @@ -350,7 +413,7 @@ public override void WriteTo(Stream stream, CancellationToken cancellation)

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

Expand Down
26 changes: 19 additions & 7 deletions sdk/core/Azure.Core/src/Shared/StringRequestContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System;
using System.Buffers;
using System.IO;
using System.Text;
using System.Threading;
Expand All @@ -11,39 +12,50 @@ namespace Azure.Core
{
internal class StringRequestContent : RequestContent
{
private readonly byte[] _bytes;
private readonly byte[] _buffer;
private readonly int _actualByteCount;

public StringRequestContent(string value)
{
_bytes = Encoding.UTF8.GetBytes(value);
#if NET6_0_OR_GREATER
var byteCount = Encoding.UTF8.GetMaxByteCount(value.Length);
_buffer = ArrayPool<byte>.Shared.Rent(byteCount);
_actualByteCount = Encoding.UTF8.GetBytes(value, _buffer);
#else
_buffer = Encoding.UTF8.GetBytes(value);
_actualByteCount = _buffer.Length;
#endif
}

public override async Task WriteToAsync(Stream stream, CancellationToken cancellation)
{
#if NET6_0_OR_GREATER
await stream.WriteAsync(_bytes.AsMemory(), cancellation).ConfigureAwait(false);
await stream.WriteAsync(_buffer.AsMemory(0, _actualByteCount), cancellation).ConfigureAwait(false);
#else
await stream.WriteAsync(_bytes, 0, _bytes.Length, cancellation).ConfigureAwait(false);
await stream.WriteAsync(_buffer, 0, _actualByteCount, cancellation).ConfigureAwait(false);
#endif
}

public override void WriteTo(Stream stream, CancellationToken cancellation)
{
#if NET6_0_OR_GREATER
stream.Write(_bytes.AsSpan());
stream.Write(_buffer.AsSpan(0, _actualByteCount));
#else
stream.Write(_bytes, 0, _bytes.Length);
stream.Write(_buffer, 0, _actualByteCount);
#endif
}

public override bool TryComputeLength(out long length)
{
length = _bytes.Length;
length = _actualByteCount;
return true;
}

public override void Dispose()
{
#if NET6_0_OR_GREATER
ArrayPool<byte>.Shared.Return(_buffer, clearArray: true);
#endif
}
}
}
Loading