|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
internal abstract class HttpBaseStream : Stream
{
public sealed override bool CanSeek => false;
public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) =>
TaskToAsyncResult.Begin(ReadAsync(buffer, offset, count, default), callback, state);
public sealed override int EndRead(IAsyncResult asyncResult) =>
TaskToAsyncResult.End<int>(asyncResult);
public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) =>
TaskToAsyncResult.Begin(WriteAsync(buffer, offset, count, default), callback, state);
public sealed override void EndWrite(IAsyncResult asyncResult) =>
TaskToAsyncResult.End(asyncResult);
public sealed override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public sealed override void SetLength(long value) => throw new NotSupportedException();
public sealed override long Length => throw new NotSupportedException();
public sealed override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public sealed override int ReadByte()
{
byte b = 0;
return Read(new Span<byte>(ref b)) == 1 ? b : -1;
}
public sealed override int Read(byte[] buffer, int offset, int count)
{
ValidateBufferArguments(buffer, offset, count);
return Read(buffer.AsSpan(offset, count));
}
public sealed override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
ValidateBufferArguments(buffer, offset, count);
return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
public override void Write(byte[] buffer, int offset, int count)
{
// This does sync-over-async, but it also should only end up being used in strange
// situations. Either a derived stream overrides this anyway, so the implementation won't be used,
// or it's being called as part of HttpContent.SerializeToStreamAsync, which means custom
// content is explicitly choosing to make a synchronous call as part of an asynchronous method.
WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
}
public sealed override void WriteByte(byte value) =>
Write(new ReadOnlySpan<byte>(in value));
public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
ValidateBufferArguments(buffer, offset, count);
return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
public override void Flush() => FlushAsync(default).GetAwaiter().GetResult();
public override Task FlushAsync(CancellationToken cancellationToken) => NopAsync(cancellationToken);
protected static Task NopAsync(CancellationToken cancellationToken) =>
cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) :
Task.CompletedTask;
//
// Methods which must be implemented by derived classes
//
public abstract override int Read(Span<byte> buffer);
public abstract override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken);
public abstract override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken);
}
}
|