< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.Framing.FramingConnection
Assembly: CoreWCF.NetFramingBase
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Channels/Framing/FramingConnection.cs
Line coverage
78%
Covered lines: 99
Uncovered lines: 27
Coverable lines: 126
Total lines: 266
Line coverage: 78.5%
Branch coverage
72%
Covered branches: 16
Total branches: 22
Branch coverage: 72.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%22100%
Reset()100%11100%
Abort()100%11100%
Abort(...)100%11100%
Abort(...)100%11100%
CloseAsync(...)100%110%
SendFaultAsync()66.66%6644.73%
GetRemoteEndPoint(...)50%4471.42%
.cctor()100%11100%
BuildNet5RemoteEndPointPropertyAccessor()50%2288.88%
SetInitializationToken(...)100%66100%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Channels/Framing/FramingConnection.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;
 5using System.Diagnostics;
 6using System.IO;
 7using System.IO.Pipelines;
 8using System.Linq.Expressions;
 9using System.Net;
 10using System.Reflection;
 11using System.Threading;
 12using System.Threading.Tasks;
 13using CoreWCF.Configuration;
 14using CoreWCF.Runtime;
 15using CoreWCF.Security;
 16using Microsoft.AspNetCore.Connections;
 17using Microsoft.AspNetCore.Http.Features;
 18using Microsoft.Extensions.Logging;
 19using Microsoft.Extensions.Logging.Abstractions;
 20
 21namespace CoreWCF.Channels.Framing
 22{
 23    public class FramingConnection
 24    {
 25        private readonly ConnectionContext _context;
 26
 8227        public FramingConnection(ConnectionContext context)
 28        {
 8229            _context = context;
 8230            Logger = context.Features.Get<ILogger>();
 8231            if (Logger== null)
 32            {
 333                Logger = NullLogger.Instance;
 34            }
 35
 8236            Transport = RawTransport = _context.Transport;
 8237            RemoteEndpoint = GetRemoteEndPoint(context);
 8238            SetInitializationToken(true);
 8239        }
 40
 52741        internal CancellationToken ChannelInitializationCancellationToken { get; private set; }
 51042        public MessageEncoderFactory MessageEncoderFactory { get; internal set; }
 53643        public StreamUpgradeAcceptor StreamUpgradeAcceptor { get; internal set; }
 21944        public ISecurityCapabilities SecurityCapabilities { get; internal set; }
 143145        public IServiceDispatcher ServiceDispatcher { get; internal set; }
 136246        public PipeReader Input => Transport.Input;
 201447        public PipeWriter Output => Transport.Output;
 369348        public IDuplexPipe Transport { get; set; }
 45349        public IDuplexPipe RawTransport { get; private set; }
 88550        internal FramingDecoder FramingDecoder { get; set; }
 22951        public Uri Via => FramingDecoder?.Via;
 38552        internal FramingMode FramingMode { get; set; }
 30953        public MessageEncoder MessageEncoder { get; internal set; }
 26554        public IFeatureCollection ConnectionFeatures => _context.Features;
 55        public SecurityMessageProperty SecurityMessageProperty
 56        {
 13657            get;
 11358            internal set;
 59        }
 123460        public bool EOF { get; internal set; }
 77261        public Memory<byte> EnvelopeBuffer { get; internal set; }
 48562        public int EnvelopeOffset { get; internal set; }
 46263        public BufferManager BufferManager { get; internal set; }
 33364        public int EnvelopeSize { get; internal set; }
 26965        public long MaxReceivedMessageSize { get; internal set; }
 40366        public int MaxBufferSize { get; internal set; }
 26967        public int ConnectionBufferSize { get; internal set; }
 26968        public TransferMode TransferMode { get; internal set; }
 23569        internal Stream RawStream { get; set; }
 80670        public ILogger Logger { get; }
 12671        public IPEndPoint RemoteEndpoint { get; }
 72
 73        internal void Reset()
 74        {
 10575            SetInitializationToken(false);
 10576            MessageEncoderFactory = default;
 10577            StreamUpgradeAcceptor = default;
 10578            SecurityCapabilities = default;
 10579            ServiceDispatcher = default;
 10580            Transport = RawTransport;
 10581            FramingDecoder = default;
 10582            FramingMode = default;
 10583            MessageEncoder = default;
 10584            SecurityMessageProperty = default;
 10585            EOF = default;
 10586            EnvelopeBuffer = default;
 10587            EnvelopeOffset = default;
 10588            BufferManager = default;
 10589            EnvelopeSize = default;
 10590            MaxReceivedMessageSize = default;
 10591            MaxBufferSize = default;
 10592            ConnectionBufferSize = default;
 10593            TransferMode = default;
 10594            RawStream = default;
 10595        }
 96
 297        public void Abort() { _context.Abort(new ConnectionAbortedException()); }
 498        public void Abort(Exception e) { _context.Abort(new ConnectionAbortedException(e.Message, e)); }
 1499        public void Abort(string reason) { _context.Abort(new ConnectionAbortedException(reason)); }
 100
 101        public Task CloseAsync(TimeSpan timeout)
 102        {
 103            // Closing should be async and should accept a timeout. There are improvements coming in future releases of 
 0104            Input.Complete();
 0105            Output.Complete();
 0106            return Task.CompletedTask;
 107        }
 108
 109        internal async Task SendFaultAsync(string faultString, int maxRead, CancellationToken cancellationToken)
 110        {
 111            //if (TD.ConnectionReaderSendFaultIsEnabled())
 112            //{
 113            //    TD.ConnectionReaderSendFault(faultString);
 114            //}
 3115            var encodedFault = new EncodedFault(faultString);
 116            try
 117            {
 3118                await Output.WriteAsync(encodedFault.EncodedBytes, cancellationToken);
 3119                await Output.FlushAsync();
 120                // Connection will be closed on completion of Task returned from NetMessageFramingConnectionHandler.OnCo
 3121            }
 0122            catch (CommunicationException e) // TODO: Consider exception filters to remvoe duplicate code
 123            {
 0124                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0125                Abort(e);
 0126                return;
 127            }
 0128            catch (OperationCanceledException e)
 129            {
 130                //if (TD.SendTimeoutIsEnabled())
 131                //{
 132                //    TD.SendTimeout(e.Message);
 133                //}
 0134                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0135                Abort(e);
 0136                return;
 137            }
 0138            catch (TimeoutException e)
 139            {
 140                //if (TD.SendTimeoutIsEnabled())
 141                //{
 142                //    TD.SendTimeout(e.Message);
 143                //}
 0144                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0145                Abort(e);
 0146                return;
 147            }
 148
 149            // make sure we read until EOF or a quota is hit
 150            ReadResult readResult;
 3151            long readTotal = 0;
 152            for (; ; )
 153            {
 154                try
 155                {
 6156                    readResult = await Input.ReadAsync(cancellationToken);
 4157                }
 1158                catch (CommunicationException e) // TODO: Exception filters?
 159                {
 1160                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 1161                    Abort(e);
 1162                    return;
 163                }
 164                // TODO: Standardize handling of OperationCanceledException/TimeoutException
 0165                catch (OperationCanceledException e)
 166                {
 167                    //if (TD.SendTimeoutIsEnabled())
 168                    //{
 169                    //    TD.SendTimeout(e.Message);
 170                    //}
 0171                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0172                    Abort(e);
 0173                    return;
 174                }
 0175                catch (TimeoutException e)
 176                {
 177                    //if (TD.SendTimeoutIsEnabled())
 178                    //{
 179                    //    TD.SendTimeout(e.Message);
 180                    //}
 0181                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0182                    Abort(e);
 0183                    return;
 184                }
 185
 4186                if (readResult.IsCompleted)
 187                {
 188                    break;
 189                }
 190
 3191                readTotal += readResult.Buffer.Length;
 3192                Input.AdvanceTo(readResult.Buffer.End);
 3193                if (readTotal > maxRead || cancellationToken.IsCancellationRequested)
 194                {
 0195                    Abort();
 1196                    return;
 197                }
 198            }
 2199        }
 200
 201        /// <summary>
 202        /// Tries to extract the remote endpoint from the given <see cref="ConnectionContext"/> in a
 203        /// version agnostic way.
 204        /// </summary>
 205        /// <param name="context">The ASP.net core connection context to extract the remote endpoint from.</param>
 206        /// <returns>The endpoint of the remote party or null if it was not provided.</returns>
 207        private static IPEndPoint GetRemoteEndPoint(ConnectionContext context)
 208        {
 209            // 1st chance: Server might provide remote endpoint via HTTP feature
 210            // (mostly the case in ASP.net core v2.x)
 82211            IHttpConnectionFeature connectionFeature = context.Features.Get<IHttpConnectionFeature>();
 82212            if (connectionFeature != null)
 213            {
 0214                return new IPEndPoint(connectionFeature.RemoteIpAddress, connectionFeature.RemotePort);
 215            }
 216
 217            // 2nd chance: on ASP.net core 5.0 the ConnectionContext has a direct Property RemoteEndpoint
 218            // via baseclass.
 82219            var net5RemoteEndPointPropertyAccessor = s_net5RemoteEndPointPropertyAccessor;
 82220            if (net5RemoteEndPointPropertyAccessor != null)
 221            {
 82222                return net5RemoteEndPointPropertyAccessor(context);
 223            }
 224
 225            // last chance: server does likely not support access to remote endpoint. could be
 226            // a non-tcp server like the ASP.net core test server
 0227            return null;
 228        }
 229
 230
 2231        private static readonly Func<ConnectionContext, IPEndPoint> s_net5RemoteEndPointPropertyAccessor =
 2232            BuildNet5RemoteEndPointPropertyAccessor();
 233
 234        private static Func<ConnectionContext, IPEndPoint> BuildNet5RemoteEndPointPropertyAccessor()
 235        {
 236            // https://github.com/dotnet/aspnetcore/blob/v5.0.9/src/Servers/Connections.Abstractions/src/BaseConnectionC
 2237            var property =
 2238                typeof(ConnectionContext).GetProperty("RemoteEndPoint", BindingFlags.Instance | BindingFlags.Public);
 2239            if (property == null)
 240            {
 0241                return null;
 242            }
 243
 244            // context => context.RemoteEndPoint as IPEndpoint
 2245            var contextParam = Expression.Parameter(typeof(ConnectionContext), "context");
 2246            return Expression.Lambda<Func<ConnectionContext, IPEndPoint>>(
 2247                 Expression.TypeAs(Expression.Property(contextParam, property),  typeof(IPEndPoint)),
 2248                contextParam
 2249            ).Compile();
 250        }
 251
 252        internal void SetInitializationToken(bool isFirstChannel)
 253        {
 254            // The first time the ChannelInitializationToken token is used, we use the ChannelInitializationTimeout. On 
 255            // we are reusing the connection, and the IdleTimeout will get used instead.
 187256            var listenOptions = ConnectionFeatures.Get<NetFramingListenOptions>();
 187257            TimeSpan connectionInitializationTimeout = isFirstChannel ? TimeSpan.FromSeconds(30) : TimeSpan.FromMinutes(
 187258            if (listenOptions != null)
 259            {
 184260                connectionInitializationTimeout = isFirstChannel ? listenOptions.ConnectionPoolSettings.ChannelInitializ
 261            }
 262
 187263            ChannelInitializationCancellationToken = new TimeoutHelper(connectionInitializationTimeout).GetCancellationT
 187264        }
 265    }
 266}