< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 46
Coverable lines: 46
Total lines: 133
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 14
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%110%
ReadMessageAsync(...)0%12120%
WriteMessageAsync(...)0%220%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Security/src/System/Net/StreamFramer.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.Globalization;
 5using System.IO;
 6using System.Net.Security;
 7using System.Threading;
 8using System.Threading.Tasks;
 9
 10namespace System.Net
 11{
 12    internal sealed class StreamFramer
 13    {
 014        private readonly FrameHeader _writeHeader = new FrameHeader();
 015        private readonly FrameHeader _curReadHeader = new FrameHeader();
 16
 017        private readonly byte[] _readHeaderBuffer = new byte[FrameHeader.Size];
 018        private readonly byte[] _writeHeaderBuffer = new byte[FrameHeader.Size];
 19        private bool _eof;
 20
 021        public FrameHeader ReadHeader => _curReadHeader;
 022        public FrameHeader WriteHeader => _writeHeader;
 23
 24        public async ValueTask<byte[]?> ReadMessageAsync<TAdapter>(Stream stream, CancellationToken cancellationToken)
 25            where TAdapter : IReadWriteAdapter
 026        {
 027            if (_eof)
 028            {
 029                return null;
 30            }
 31
 032            byte[] buffer = _readHeaderBuffer;
 33
 034            int bytesRead = await TAdapter.ReadAtLeastAsync(
 035                stream, buffer, buffer.Length, throwOnEndOfStream: false, cancellationToken).ConfigureAwait(false);
 036            if (bytesRead < buffer.Length)
 037            {
 038                if (bytesRead == 0)
 039                {
 40                    // m_Eof, return null
 041                    _eof = true;
 042                    return null;
 43                }
 044                throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed));
 45            }
 46
 047            _curReadHeader.CopyFrom(buffer, 0);
 048            if (_curReadHeader.PayloadSize > FrameHeader.MaxMessageSize)
 049            {
 050                throw new InvalidOperationException(SR.Format(SR.net_frame_size,
 051                                                               FrameHeader.MaxMessageSize,
 052                                                               _curReadHeader.PayloadSize.ToString(NumberFormatInfo.Inva
 53            }
 54
 055            buffer = new byte[_curReadHeader.PayloadSize];
 56
 057            if (buffer.Length > 0)
 058            {
 059                bytesRead = await TAdapter.ReadAtLeastAsync(
 060                    stream, buffer, buffer.Length, throwOnEndOfStream: false, cancellationToken).ConfigureAwait(false);
 061                if (bytesRead < buffer.Length)
 062                {
 063                    throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed));
 64                }
 065            }
 066            return buffer;
 067        }
 68
 69        public async Task WriteMessageAsync<TAdapter>(Stream stream, byte[] message, CancellationToken cancellationToken
 70            where TAdapter : IReadWriteAdapter
 071        {
 072            _writeHeader.PayloadSize = message.Length;
 073            _writeHeader.CopyTo(_writeHeaderBuffer, 0);
 74
 075            await TAdapter.WriteAsync(stream, _writeHeaderBuffer, cancellationToken).ConfigureAwait(false);
 076            if (message.Length != 0)
 077            {
 078                await TAdapter.WriteAsync(stream, message, cancellationToken).ConfigureAwait(false);
 079            }
 080        }
 81    }
 82
 83    // Describes the header used in framing of the stream data.
 84    internal sealed class FrameHeader
 85    {
 86        public const int IgnoreValue = -1;
 87        public const int HandshakeDoneId = 20;
 88        public const int HandshakeErrId = 21;
 89        public const int HandshakeId = 22;
 90        public const int DefaultMajorV = 1;
 91        public const int DefaultMinorV = 0;
 92        public const int Size = 5;
 93        public const int MaxMessageSize = 0xFFFF;
 94
 95        private int _payloadSize = -1;
 96
 97        public int MessageId { get; set; } = HandshakeId;
 98        public int MajorV { get; private set; } = DefaultMajorV;
 99        public int MinorV { get; private set; } = DefaultMinorV;
 100
 101        public int PayloadSize
 102        {
 103            get => _payloadSize;
 104            set
 105            {
 106                if (value > MaxMessageSize)
 107                {
 108                    throw new ArgumentException(SR.Format(SR.net_frame_max_size, MaxMessageSize, value), nameof(PayloadS
 109                }
 110
 111                _payloadSize = value;
 112            }
 113        }
 114
 115        public void CopyTo(byte[] dest, int start)
 116        {
 117            dest[start++] = (byte)MessageId;
 118            dest[start++] = (byte)MajorV;
 119            dest[start++] = (byte)MinorV;
 120            dest[start++] = (byte)((_payloadSize >> 8) & 0xFF);
 121            dest[start] = (byte)(_payloadSize & 0xFF);
 122        }
 123
 124        public void CopyFrom(byte[] bytes, int start)
 125        {
 126            MessageId = bytes[start++];
 127            MajorV = bytes[start++];
 128            MinorV = bytes[start++];
 129            _payloadSize = (bytes[start++] << 8) | bytes[start];
 130        }
 131    }
 132}
 133