< Summary

Information
Class: System.Net.Http.StreamContent
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\StreamContent.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 99
Coverable lines: 99
Total lines: 190
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 18
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\StreamContent.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6using System.IO;
 7using System.Runtime.CompilerServices;
 8using System.Threading;
 9using System.Threading.Tasks;
 10
 11namespace System.Net.Http
 12{
 13    public class StreamContent : HttpContent
 14    {
 15        private Stream _content;
 16        private int _bufferSize;
 17        private bool _contentConsumed;
 18        private long _start;
 19
 020        public StreamContent(Stream content)
 021        {
 022            ArgumentNullException.ThrowIfNull(content);
 23
 24            // Indicate that we should use default buffer size by setting size to 0.
 025            InitializeContent(content, 0);
 026        }
 27
 028        public StreamContent(Stream content, int bufferSize)
 029        {
 030            ArgumentNullException.ThrowIfNull(content);
 031            ArgumentOutOfRangeException.ThrowIfNegativeOrZero(bufferSize);
 32
 033            InitializeContent(content, bufferSize);
 034        }
 35
 36        [MemberNotNull(nameof(_content))]
 37        private void InitializeContent(Stream content, int bufferSize)
 038        {
 039            _content = content;
 040            _bufferSize = bufferSize;
 041            if (content.CanSeek)
 042            {
 043                _start = content.Position;
 044            }
 045            if (NetEventSource.Log.IsEnabled()) NetEventSource.Associate(this, content);
 046        }
 47
 48        protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellati
 049        {
 050            Debug.Assert(stream != null);
 051            PrepareContent();
 52            // If the stream can't be re-read, make sure that it gets disposed once it is consumed.
 053            StreamToStreamCopy.Copy(_content, stream, _bufferSize, !_content.CanSeek);
 054        }
 55
 56        protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) =>
 057            SerializeToStreamAsyncCore(stream, default);
 58
 59        protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cance
 60            // Only skip the original protected virtual SerializeToStreamAsync if this
 61            // isn't a derived type that may have overridden the behavior.
 062            GetType() == typeof(StreamContent) ? SerializeToStreamAsyncCore(stream, cancellationToken) :
 063            base.SerializeToStreamAsync(stream, context, cancellationToken);
 64
 65        private Task SerializeToStreamAsyncCore(Stream stream, CancellationToken cancellationToken)
 066        {
 067            Debug.Assert(stream != null);
 068            PrepareContent();
 069            return StreamToStreamCopy.CopyAsync(
 070                _content,
 071                stream,
 072                _bufferSize,
 073                !_content.CanSeek, // If the stream can't be re-read, make sure that it gets disposed once it is consume
 074                cancellationToken);
 075        }
 76
 77        protected internal override bool TryComputeLength(out long length)
 078        {
 079            if (_content.CanSeek)
 080            {
 081                length = _content.Length - _start;
 082                return true;
 83            }
 84            else
 085            {
 086                length = 0;
 087                return false;
 88            }
 089        }
 90
 91        protected override void Dispose(bool disposing)
 092        {
 093            if (disposing)
 094            {
 095                _content.Dispose();
 096            }
 097            base.Dispose(disposing);
 098        }
 99
 100        protected override Stream CreateContentReadStream(CancellationToken cancellationToken)
 0101        {
 0102            SeekToStartIfSeekable();
 0103            return new ReadOnlyStream(_content);
 0104        }
 105
 106        protected override Task<Stream> CreateContentReadStreamAsync()
 0107        {
 0108            SeekToStartIfSeekable();
 109            // Wrap the stream with a read-only stream to prevent someone from writing to the stream.
 0110            return Task.FromResult<Stream>(new ReadOnlyStream(_content));
 0111        }
 112
 113        internal override Stream? TryCreateContentReadStream() =>
 0114            GetType() == typeof(StreamContent) ? new ReadOnlyStream(_content) : // type check ensures we use possible de
 0115            null;
 116
 0117        internal override bool AllowDuplex => false;
 118
 119        private void PrepareContent()
 0120        {
 0121            if (_contentConsumed)
 0122            {
 123                // If the content needs to be written to a target stream a 2nd time, then the stream must support
 124                // seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target
 125                // stream (e.g. a NetworkStream).
 0126                if (_content.CanSeek)
 0127                {
 0128                    _content.Position = _start;
 0129                }
 130                else
 0131                {
 0132                    throw new InvalidOperationException(SR.net_http_content_stream_already_read);
 133                }
 0134            }
 135
 0136            _contentConsumed = true;
 0137        }
 138
 139        private void SeekToStartIfSeekable()
 0140        {
 0141            if (_content.CanSeek)
 0142            {
 0143                _content.Position = _start;
 0144            }
 0145        }
 146
 147        private sealed class ReadOnlyStream : DelegatingStream
 148        {
 0149            public ReadOnlyStream(Stream innerStream) : base(innerStream)
 0150            {
 0151            }
 152
 0153            public override bool CanWrite => false;
 154
 0155            public override void Flush() { }
 156
 0157            public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
 158
 159            public override void SetLength(long value) =>
 0160                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 161
 162            public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, objec
 0163                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 164
 165            public override void EndWrite(IAsyncResult asyncResult) =>
 0166                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 167
 168            public override void Write(byte[] buffer, int offset, int count) =>
 0169                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 170
 171            public override void Write(ReadOnlySpan<byte> buffer) =>
 0172                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 173
 174            public override void WriteByte(byte value) =>
 0175                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 176
 177            public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) =
 0178                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 179
 180            public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = defa
 0181                throw new NotSupportedException(SR.net_http_content_readonly_stream);
 182
 183            public override int WriteTimeout
 184            {
 0185                get => throw new InvalidOperationException(SR.net_http_content_readonly_stream);
 0186                set => throw new InvalidOperationException(SR.net_http_content_readonly_stream);
 187            }
 188        }
 189    }
 190}