< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.Framing.ServerModeDecoder
Assembly: CoreWCF.NetFramingBase
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Channels/Framing/FramingDecoder.cs
Line coverage
74%
Covered lines: 50
Uncovered lines: 17
Coverable lines: 67
Total lines: 1326
Line coverage: 74.6%
Branch coverage
65%
Covered branches: 13
Total branches: 20
Branch coverage: 65%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
Decode(...)83.33%6687.87%
Reset()100%11100%
ReadModeAsync()87.5%8872.22%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Channels/Framing/FramingDecoder.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.Buffers;
 6using System.Globalization;
 7using System.IO;
 8using System.IO.Pipelines;
 9using System.Text;
 10using System.Threading.Tasks;
 11using CoreWCF.Runtime;
 12using Microsoft.Extensions.Logging;
 13
 14namespace CoreWCF.Channels.Framing
 15{
 16    internal static class DecoderHelper
 17    {
 18        public static void ValidateSize(long size)
 19        {
 20            if (size <= 0)
 21            {
 22                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(size), 
 23            }
 24        }
 25    }
 26
 27    internal struct IntDecoder
 28    {
 29        public IntDecoder(ILogger logger)
 30        {
 31            Logger = logger;
 32            IsValueDecoded = false;
 33            _value = 0;
 34            _index = 0;
 35        }
 36
 37        private int _value;
 38        private short _index;
 39        private const int LastIndex = 4;
 40
 41        public int Value
 42        {
 43            get
 44            {
 45                if (!IsValueDecoded)
 46                {
 47                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 48                }
 49
 50                return _value;
 51            }
 52        }
 53
 54        public bool IsValueDecoded { get; private set; }
 55
 56        private ILogger Logger { get; }
 57
 58        public void Reset()
 59        {
 60            _index = 0;
 61            _value = 0;
 62            IsValueDecoded = false;
 63        }
 64
 65        public int Decode(ReadOnlySequence<byte> buffer)
 66        {
 67            DecoderHelper.ValidateSize(buffer.Length);
 68            if (IsValueDecoded)
 69            {
 70                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingValueN
 71            }
 72            int bytesConsumed = 0;
 73
 74            while (bytesConsumed < buffer.Length)
 75            {
 76                ReadOnlySpan<byte> data = buffer.First.Span;
 77                int next = data[0];
 78                _value |= (next & 0x7F) << (_index * 7);
 79                bytesConsumed++;
 80                if (_index == LastIndex && (next & 0xF8) != 0)
 81                {
 82                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.FramingSizeToo
 83                }
 84                Logger.DecodingInt(next, _index,_value);
 85                _index++;
 86                if ((next & 0x80) == 0)
 87                {
 88                    IsValueDecoded = true;
 89                    break;
 90                }
 91                buffer = buffer.Slice(buffer.GetPosition(1));
 92            }
 93            return bytesConsumed;
 94        }
 95    }
 96
 97    internal abstract class StringDecoder
 98    {
 99        private int _encodedSize;
 100        private byte[] _encodedBytes;
 101        private int _bytesNeeded;
 102        private string _value;
 103        private State _currentState;
 104        private IntDecoder _sizeDecoder;
 105        private readonly int _sizeQuota;
 106        private int _valueLengthInBytes;
 107
 108        public StringDecoder(int sizeQuota, ILogger logger)
 109        {
 110            Logger = logger;
 111            _sizeQuota = sizeQuota;
 112            _sizeDecoder = new IntDecoder(logger);
 113            Reset();
 114        }
 115
 116        protected ILogger Logger { get; }
 117
 118        public bool IsValueDecoded
 119        {
 120            get { return CurrentState == State.Done; }
 121        }
 122
 123        public string Value
 124        {
 125            get
 126            {
 127                if (CurrentState != State.Done)
 128                {
 129                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 130                }
 131
 132                return _value;
 133            }
 134        }
 135
 136        public State CurrentState { get => _currentState; private set => _currentState = value; }
 137
 138        public int Decode(ReadOnlySequence<byte> buffer)
 139        {
 140            DecoderHelper.ValidateSize(buffer.Length);
 141
 142            int bytesConsumed;
 143            Logger.LogStartState(this);
 144            switch (CurrentState)
 145            {
 146                case State.ReadingSize:
 147                    bytesConsumed = _sizeDecoder.Decode(buffer);
 148                    if (_sizeDecoder.IsValueDecoded)
 149                    {
 150                        _encodedSize = _sizeDecoder.Value;
 151                        if (_encodedSize > _sizeQuota)
 152                        {
 153                            Exception quotaExceeded = OnSizeQuotaExceeded(_encodedSize);
 154                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(quotaExceeded);
 155                        }
 156                        if (_encodedBytes == null || _encodedBytes.Length < _encodedSize)
 157                        {
 158                            _encodedBytes = Fx.AllocateByteArray(_encodedSize);
 159                            _value = null;
 160                        }
 161                        CurrentState = State.ReadingBytes;
 162                        _bytesNeeded = _encodedSize;
 163                    }
 164                    break;
 165                case State.ReadingBytes:
 166                    if (_value != null && _valueLengthInBytes == _encodedSize && _bytesNeeded == _encodedSize &&
 167                        buffer.Length >= _encodedSize && CompareBuffers(_encodedBytes, buffer))
 168                    {
 169                        bytesConsumed = _bytesNeeded;
 170                        OnComplete(_value);
 171                    }
 172                    else
 173                    {
 174                        bytesConsumed = _bytesNeeded;
 175                        if (buffer.Length < _bytesNeeded)
 176                        {
 177                            bytesConsumed = (int)buffer.Length;
 178                        }
 179
 180                        Span<byte> span = _encodedBytes;
 181                        Span<byte> slicedBytes = span.Slice(_encodedSize - _bytesNeeded, bytesConsumed);
 182                        ReadOnlySequence<byte> tempBuffer = buffer.Slice(0, bytesConsumed);
 183                        tempBuffer.CopyTo(slicedBytes);
 184                        _bytesNeeded -= bytesConsumed;
 185                        if (_bytesNeeded == 0)
 186                        {
 187                            _value = Encoding.UTF8.GetString(_encodedBytes, 0, _encodedSize);
 188                            _valueLengthInBytes = _encodedSize;
 189                            Logger.StringDecoded(_value);
 190                            OnComplete(_value);
 191                        }
 192                    }
 193                    break;
 194                default:
 195                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.InvalidDecoder
 196            }
 197
 198            Logger.LogEndState(this, bytesConsumed);
 199            return bytesConsumed;
 200        }
 201
 202        protected virtual void OnComplete(string value)
 203        {
 204            CurrentState = State.Done;
 205        }
 206
 207        private static bool CompareBuffers(byte[] buffer1, ReadOnlySequence<byte> buffer2)
 208        {
 209            byte[] buff = buffer2.ToArray();
 210            for (int i = 0; i < buffer1.Length; i++)
 211            {
 212                if (buffer1[i] != buff[i])
 213                {
 214                    return false;
 215                }
 216            }
 217            return true;
 218        }
 219
 220        protected abstract Exception OnSizeQuotaExceeded(int size);
 221
 222        public void Reset()
 223        {
 224            CurrentState = State.ReadingSize;
 225            _sizeDecoder.Reset();
 226        }
 227
 228        public enum State
 229        {
 230            ReadingSize,
 231            ReadingBytes,
 232            Done,
 233        }
 234    }
 235
 236    internal class ViaStringDecoder : StringDecoder
 237    {
 238        private Uri _via;
 239
 240        public ViaStringDecoder(int sizeQuota, ILogger logger)
 241            : base(sizeQuota, logger)
 242        {
 243        }
 244
 245        protected override Exception OnSizeQuotaExceeded(int size)
 246        {
 247            Exception result = new InvalidDataException(SR.Format(SR.FramingViaTooLong, size));
 248            FramingEncodingString.AddFaultString(result, FramingEncodingString.ViaTooLongFault);
 249            return result;
 250        }
 251
 252        protected override void OnComplete(string value)
 253        {
 254            try
 255            {
 256                _via = new Uri(value);
 257                base.OnComplete(value);
 258            }
 259            catch (UriFormatException exception)
 260            {
 261                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.Format(SR.FramingV
 262            }
 263        }
 264
 265        public Uri ValueAsUri
 266        {
 267            get
 268            {
 269                if (!IsValueDecoded)
 270                {
 271                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 272                }
 273
 274                return _via;
 275            }
 276        }
 277    }
 278
 279    internal class FaultStringDecoder : StringDecoder
 280    {
 281        internal const int FaultSizeQuota = 256;
 282
 283        public FaultStringDecoder(ILogger logger)
 284            : base(FaultSizeQuota, logger)
 285        {
 286        }
 287
 288        protected override Exception OnSizeQuotaExceeded(int size)
 289        {
 290            return new InvalidDataException(SR.Format(SR.FramingFaultTooLong, size));
 291        }
 292    }
 293
 294    internal class ContentTypeStringDecoder : StringDecoder
 295    {
 296        public ContentTypeStringDecoder(int sizeQuota, ILogger logger)
 297            : base(sizeQuota, logger)
 298        {
 299        }
 300
 301        protected override Exception OnSizeQuotaExceeded(int size)
 302        {
 303            Exception result = new InvalidDataException(SR.Format(SR.FramingContentTypeTooLong, size));
 304            FramingEncodingString.AddFaultString(result, FramingEncodingString.ContentTypeTooLongFault);
 305            return result;
 306        }
 307
 308        public static string GetString(FramingEncodingType type)
 309        {
 310            switch (type)
 311            {
 312                case FramingEncodingType.Soap11Utf8:
 313                    return FramingEncodingString.Soap11Utf8;
 314                case FramingEncodingType.Soap11Utf16:
 315                    return FramingEncodingString.Soap11Utf16;
 316                case FramingEncodingType.Soap11Utf16FFFE:
 317                    return FramingEncodingString.Soap11Utf16FFFE;
 318                case FramingEncodingType.Soap12Utf8:
 319                    return FramingEncodingString.Soap12Utf8;
 320                case FramingEncodingType.Soap12Utf16:
 321                    return FramingEncodingString.Soap12Utf16;
 322                case FramingEncodingType.Soap12Utf16FFFE:
 323                    return FramingEncodingString.Soap12Utf16FFFE;
 324                case FramingEncodingType.MTOM:
 325                    return FramingEncodingString.MTOM;
 326                case FramingEncodingType.Binary:
 327                    return FramingEncodingString.Binary;
 328                case FramingEncodingType.BinarySession:
 329                    return FramingEncodingString.BinarySession;
 330                case FramingEncodingType.ExtendedBinaryGZip:
 331                    return FramingEncodingString.ExtendedBinaryGZip;
 332                case FramingEncodingType.ExtendedBinarySessionGZip:
 333                    return FramingEncodingString.ExtendedBinarySessionGZip;
 334                case FramingEncodingType.ExtendedBinaryDeflate:
 335                    return FramingEncodingString.ExtendedBinaryDeflate;
 336                case FramingEncodingType.ExtendedBinarySessionDeflate:
 337                    return FramingEncodingString.ExtendedBinarySessionDeflate;
 338                default:
 339                    return "unknown" + ((int)type).ToString(CultureInfo.InvariantCulture);
 340            }
 341        }
 342    }
 343
 344    internal abstract class FramingDecoder
 345    {
 346        protected FramingDecoder(ILogger logger) => Logger = logger;
 347
 348        protected abstract string CurrentStateAsString { get; }
 349
 350        public virtual string ContentType { get { throw new NotImplementedException(); } }
 351
 352        protected ILogger Logger { get; }
 353
 354        public virtual Uri Via { get { throw new NotImplementedException(); } }
 355
 356        public abstract int Decode(ReadOnlySequence<byte> buffer);
 357
 358        protected void ValidateFramingMode(FramingMode mode)
 359        {
 360            switch (mode)
 361            {
 362                case FramingMode.Singleton:
 363                case FramingMode.Duplex:
 364                case FramingMode.Simplex:
 365                case FramingMode.SingletonSized:
 366                    break;
 367                default:
 368                    {
 369                        Exception exception = CreateException(new InvalidDataException(SR.Format(
 370                            SR.FramingModeNotSupported, mode.ToString())), FramingEncodingString.UnsupportedModeFault);
 371                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
 372                    }
 373            }
 374        }
 375
 376        protected void ValidateRecordType(FramingRecordType expectedType, FramingRecordType foundType)
 377        {
 378            if (foundType != expectedType)
 379            {
 380                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidRecordTypeException(expectedType,
 381            }
 382        }
 383
 384        // special validation for Preamble Ack for usability purposes (MB#39593)
 385        protected void ValidatePreambleAck(FramingRecordType foundType)
 386        {
 387            if (foundType != FramingRecordType.PreambleAck)
 388            {
 389                Exception inner = CreateInvalidRecordTypeException(FramingRecordType.PreambleAck, foundType);
 390                string exceptionString;
 391                if (((byte)foundType == 'h') || ((byte)foundType == 'H'))
 392                {
 393                    exceptionString = SR.PreambleAckIncorrectMaybeHttp;
 394                }
 395                else
 396                {
 397                    exceptionString = SR.PreambleAckIncorrect;
 398                }
 399                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(exceptionString, inner))
 400            }
 401        }
 402
 403        private Exception CreateInvalidRecordTypeException(FramingRecordType expectedType, FramingRecordType foundType)
 404        {
 405            return new InvalidDataException(SR.Format(SR.FramingRecordTypeMismatch, expectedType.ToString(), foundType.T
 406        }
 407
 408        protected void ValidateMajorVersion(int majorVersion)
 409        {
 410            if (majorVersion != FramingVersion.Major)
 411            {
 412                Exception exception = CreateException(new InvalidDataException(SR.Format(
 413                    SR.FramingVersionNotSupported, majorVersion)), FramingEncodingString.UnsupportedVersionFault);
 414                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
 415            }
 416        }
 417
 418        public Exception CreatePrematureEOFException()
 419        {
 420            return CreateException(new InvalidDataException(SR.FramingPrematureEOF));
 421        }
 422
 423        protected Exception CreateException(InvalidDataException innerException, string framingFault)
 424        {
 425            Exception result = CreateException(innerException);
 426            FramingEncodingString.AddFaultString(result, framingFault);
 427            return result;
 428        }
 429
 430        protected Exception CreateException(InvalidDataException innerException)
 431        {
 432            // TODO: Can the position still be recovered?
 433            return new ProtocolException(SR.Format(SR.FramingError, /*StreamPosition*/ -1, CurrentStateAsString),
 434                innerException);
 435        }
 436    }
 437
 438    // Pattern:
 439    //   Done
 440    internal class ServerModeDecoder : FramingDecoder
 441    {
 442        private int _majorVersion;
 443        private int _minorVersion;
 444        private FramingMode _mode;
 445
 118446        public ServerModeDecoder(ILogger logger) : base(logger)
 447        {
 118448            Reset();
 118449        }
 450
 451        public override int Decode(ReadOnlySequence<byte> buffer)
 452        {
 575453            DecoderHelper.ValidateSize(buffer.Length);
 575454            ReadOnlySpan<byte> data = buffer.First.Span;
 455
 456            try
 457            {
 458                int bytesConsumed;
 575459                Logger.LogStartState(this);
 575460                switch (CurrentState)
 461                {
 462                    case State.ReadingVersionRecord:
 115463                        ValidateRecordType(FramingRecordType.Version, (FramingRecordType)data[0]);
 115464                        CurrentState = State.ReadingMajorVersion;
 115465                        bytesConsumed = 1;
 115466                        break;
 467                    case State.ReadingMajorVersion:
 115468                        _majorVersion = data[0];
 115469                        ValidateMajorVersion(_majorVersion);
 115470                        CurrentState = State.ReadingMinorVersion;
 115471                        bytesConsumed = 1;
 115472                        break;
 473                    case State.ReadingMinorVersion:
 115474                        _minorVersion = data[0];
 115475                        CurrentState = State.ReadingModeRecord;
 115476                        bytesConsumed = 1;
 115477                        break;
 478                    case State.ReadingModeRecord:
 115479                        ValidateRecordType(FramingRecordType.Mode, (FramingRecordType)data[0]);
 115480                        CurrentState = State.ReadingModeValue;
 115481                        bytesConsumed = 1;
 115482                        break;
 483                    case State.ReadingModeValue:
 115484                        _mode = (FramingMode)data[0];
 115485                        ValidateFramingMode(_mode);
 115486                        CurrentState = State.Done;
 115487                        bytesConsumed = 1;
 115488                        break;
 489                    default:
 0490                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 0491                            CreateException(new InvalidDataException(SR.InvalidDecoderStateMachine)));
 492                }
 493
 575494                Logger.LogEndState(this, bytesConsumed);
 575495                return bytesConsumed;
 496            }
 0497            catch (InvalidDataException e)
 498            {
 0499                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
 500            }
 575501        }
 502
 503        public void Reset()
 504        {
 118505            CurrentState = State.ReadingVersionRecord;
 118506        }
 507
 508        internal async Task<bool> ReadModeAsync(PipeReader inputPipe, System.Threading.CancellationToken cancelToken)
 509        {
 510            ReadOnlySequence<byte> buffer;
 0511            while (true)
 512            {
 118513                ReadResult readResult = await inputPipe.ReadAsync(cancelToken);
 117514                if (readResult.IsCompleted)
 515                {
 2516                    return false;
 517                }
 518
 115519                buffer = readResult.Buffer;
 520
 575521                while (buffer.Length > 0)
 522                {
 523                    int bytesDecoded;
 524                    try
 525                    {
 575526                        bytesDecoded = Decode(buffer);
 575527                    }
 0528                    catch (CommunicationException e)
 529                    {
 530                        // Need to call inputPipe.AdvanceTo so that the code that handles the exception
 531                        // can send the fault and drain the input pipe by calling ReadAsync again.
 0532                        inputPipe.AdvanceTo(buffer.Start);
 0533                        throw;
 534                    }
 535
 575536                    if (bytesDecoded > 0)
 537                    {
 575538                        buffer = buffer.Slice(bytesDecoded);
 539                    }
 540
 575541                    if (CurrentState == State.Done)
 542                    {
 115543                        inputPipe.AdvanceTo(buffer.Start);
 115544                        return true;
 545                    }
 546                }
 547
 0548                inputPipe.AdvanceTo(buffer.End);
 549            }
 117550        }
 551
 3108552        public State CurrentState { get; private set; }
 553
 0554        protected override string CurrentStateAsString => CurrentState.ToString();
 555
 556        public FramingMode Mode
 557        {
 558            get
 559            {
 115560                if (CurrentState != State.Done)
 561                {
 0562                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 563                }
 564
 115565                return _mode;
 566            }
 567        }
 568
 569        public int MajorVersion
 570        {
 571            get
 572            {
 0573                if (CurrentState != State.Done)
 574                {
 0575                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 576                }
 577
 0578                return _majorVersion;
 579            }
 580        }
 581
 582        public int MinorVersion
 583        {
 584            get
 585            {
 0586                if (CurrentState != State.Done)
 587                {
 0588                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 589                }
 590
 0591                return _minorVersion;
 592            }
 593        }
 594
 595        public enum State
 596        {
 597            ReadingVersionRecord,
 598            ReadingMajorVersion,
 599            ReadingMinorVersion,
 600            ReadingModeRecord,
 601            ReadingModeValue,
 602            Done,
 603        }
 604    }
 605
 606    // Used for Duplex/Simplex
 607    // Pattern:
 608    //   Start,
 609    //   (UpgradeRequest, upgrade-content-type)*,
 610    //   (EnvelopeStart, ReadingEnvelopeBytes*, EnvelopeEnd)*,
 611    //   End
 612    internal class ServerSessionDecoder : FramingDecoder
 613    {
 614        private readonly ViaStringDecoder _viaDecoder;
 615        private readonly StringDecoder _contentTypeDecoder;
 616        private IntDecoder _sizeDecoder;
 617        private string _contentType;
 618        private int _envelopeBytesNeeded;
 619        private int _envelopeSize;
 620        private string _upgrade;
 621
 622        public ServerSessionDecoder(int maxViaLength, int maxContentTypeLength, ILogger logger) : base(logger)
 623        {
 624            _viaDecoder = new ViaStringDecoder(maxViaLength, logger);
 625            _contentTypeDecoder = new ContentTypeStringDecoder(maxContentTypeLength, logger);
 626            _sizeDecoder = new IntDecoder(logger);
 627            Reset();
 628        }
 629
 630        public State CurrentState { get; private set; }
 631
 632        protected override string CurrentStateAsString => CurrentState.ToString();
 633
 634        public override string ContentType
 635        {
 636            get
 637            {
 638                if (CurrentState < State.PreUpgradeStart)
 639                {
 640                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 641                }
 642
 643                return _contentType;
 644            }
 645        }
 646
 647        public override Uri Via
 648        {
 649            get
 650            {
 651                if (CurrentState < State.ReadingContentTypeRecord)
 652                {
 653                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 654                }
 655
 656                return _viaDecoder.ValueAsUri;
 657            }
 658        }
 659
 660        public void Reset()
 661        {
 662            CurrentState = State.ReadingViaRecord;
 663        }
 664
 665        public string Upgrade
 666        {
 667            get
 668            {
 669                if (CurrentState != State.UpgradeRequest)
 670                {
 671                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 672                }
 673
 674                return _upgrade;
 675            }
 676        }
 677
 678        public int EnvelopeSize
 679        {
 680            get
 681            {
 682                if (CurrentState < State.EnvelopeStart)
 683                {
 684                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 685                }
 686
 687                return _envelopeSize;
 688            }
 689        }
 690
 691        public override int Decode(ReadOnlySequence<byte> buffer)
 692        {
 693            DecoderHelper.ValidateSize(buffer.Length);
 694            ReadOnlySpan<byte> data = buffer.First.Span;
 695            try
 696            {
 697                int bytesConsumed;
 698                FramingRecordType recordType;
 699                Logger.LogStartState(this);
 700                switch (CurrentState)
 701                {
 702                    case State.ReadingViaRecord:
 703                        recordType = (FramingRecordType)data[0];
 704                        ValidateRecordType(FramingRecordType.Via, recordType);
 705                        bytesConsumed = 1;
 706                        _viaDecoder.Reset();
 707                        CurrentState = State.ReadingViaString;
 708                        break;
 709                    case State.ReadingViaString:
 710                        bytesConsumed = _viaDecoder.Decode(buffer);
 711                        if (_viaDecoder.IsValueDecoded)
 712                        {
 713                            CurrentState = State.ReadingContentTypeRecord;
 714                        }
 715                        break;
 716                    case State.ReadingContentTypeRecord:
 717                        recordType = (FramingRecordType)data[0];
 718                        if (recordType == FramingRecordType.KnownEncoding)
 719                        {
 720                            bytesConsumed = 1;
 721                            CurrentState = State.ReadingContentTypeByte;
 722                        }
 723                        else
 724                        {
 725                            ValidateRecordType(FramingRecordType.ExtensibleEncoding, recordType);
 726                            bytesConsumed = 1;
 727                            _contentTypeDecoder.Reset();
 728                            CurrentState = State.ReadingContentTypeString;
 729                        }
 730                        break;
 731                    case State.ReadingContentTypeByte:
 732                        _contentType = ContentTypeStringDecoder.GetString((FramingEncodingType)data[0]);
 733                        bytesConsumed = 1;
 734                        CurrentState = State.PreUpgradeStart;
 735                        break;
 736                    case State.ReadingContentTypeString:
 737                        bytesConsumed = _contentTypeDecoder.Decode(buffer);
 738                        if (_contentTypeDecoder.IsValueDecoded)
 739                        {
 740                            CurrentState = State.PreUpgradeStart;
 741                            _contentType = _contentTypeDecoder.Value;
 742                        }
 743                        break;
 744                    case State.PreUpgradeStart:
 745                        bytesConsumed = 0;
 746                        CurrentState = State.ReadingUpgradeRecord;
 747                        break;
 748                    case State.ReadingUpgradeRecord:
 749                        recordType = (FramingRecordType)data[0];
 750                        if (recordType == FramingRecordType.UpgradeRequest)
 751                        {
 752                            bytesConsumed = 1;
 753                            _contentTypeDecoder.Reset();
 754                            CurrentState = State.ReadingUpgradeString;
 755                        }
 756                        else
 757                        {
 758                            bytesConsumed = 0;
 759                            CurrentState = State.ReadingPreambleEndRecord;
 760                        }
 761                        break;
 762                    case State.ReadingUpgradeString:
 763                        bytesConsumed = _contentTypeDecoder.Decode(buffer);
 764                        if (_contentTypeDecoder.IsValueDecoded)
 765                        {
 766                            CurrentState = State.UpgradeRequest;
 767                            _upgrade = _contentTypeDecoder.Value;
 768                        }
 769                        break;
 770                    case State.UpgradeRequest:
 771                        bytesConsumed = 0;
 772                        CurrentState = State.ReadingUpgradeRecord;
 773                        break;
 774                    case State.ReadingPreambleEndRecord:
 775                        recordType = (FramingRecordType)data[0];
 776                        ValidateRecordType(FramingRecordType.PreambleEnd, recordType);
 777                        bytesConsumed = 1;
 778                        CurrentState = State.Start;
 779                        break;
 780                    case State.Start:
 781                        bytesConsumed = 0;
 782                        CurrentState = State.ReadingEndRecord;
 783                        break;
 784                    case State.ReadingEndRecord:
 785                        recordType = (FramingRecordType)data[0];
 786                        if (recordType == FramingRecordType.End)
 787                        {
 788                            bytesConsumed = 1;
 789                            CurrentState = State.End;
 790                        }
 791                        else
 792                        {
 793                            bytesConsumed = 0;
 794                            CurrentState = State.ReadingEnvelopeRecord;
 795                        }
 796                        break;
 797                    case State.ReadingEnvelopeRecord:
 798                        ValidateRecordType(FramingRecordType.SizedEnvelope, (FramingRecordType)data[0]);
 799                        bytesConsumed = 1;
 800                        CurrentState = State.ReadingEnvelopeSize;
 801                        _sizeDecoder.Reset();
 802                        break;
 803                    case State.ReadingEnvelopeSize:
 804                        bytesConsumed = _sizeDecoder.Decode(buffer);
 805                        if (_sizeDecoder.IsValueDecoded)
 806                        {
 807                            CurrentState = State.EnvelopeStart;
 808                            _envelopeSize = _sizeDecoder.Value;
 809                            _envelopeBytesNeeded = _envelopeSize;
 810                        }
 811                        break;
 812                    case State.EnvelopeStart:
 813                        bytesConsumed = 0;
 814                        CurrentState = State.ReadingEnvelopeBytes;
 815                        break;
 816                    case State.ReadingEnvelopeBytes:
 817                        bytesConsumed = (int)buffer.Length;
 818                        if (bytesConsumed > _envelopeBytesNeeded)
 819                        {
 820                            bytesConsumed = _envelopeBytesNeeded;
 821                        }
 822
 823                        _envelopeBytesNeeded -= bytesConsumed;
 824                        if (_envelopeBytesNeeded == 0)
 825                        {
 826                            CurrentState = State.EnvelopeEnd;
 827                        }
 828
 829                        break;
 830                    case State.EnvelopeEnd:
 831                        bytesConsumed = 0;
 832                        CurrentState = State.ReadingEndRecord;
 833                        break;
 834                    case State.End:
 835                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 836                            CreateException(new InvalidDataException(SR.FramingAtEnd)));
 837                    default:
 838                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 839                            CreateException(new InvalidDataException(SR.InvalidDecoderStateMachine)));
 840                }
 841
 842                Logger.LogEndState(this, bytesConsumed);
 843                return bytesConsumed;
 844            }
 845            catch (InvalidDataException e)
 846            {
 847                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
 848            }
 849        }
 850
 851        public enum State
 852        {
 853            ReadingViaRecord,
 854            ReadingViaString,
 855            ReadingContentTypeRecord,
 856            ReadingContentTypeString,
 857            ReadingContentTypeByte,
 858            PreUpgradeStart,
 859            ReadingUpgradeRecord,
 860            ReadingUpgradeString,
 861            UpgradeRequest,
 862            ReadingPreambleEndRecord,
 863            Start,
 864            ReadingEnvelopeRecord,
 865            ReadingEnvelopeSize,
 866            EnvelopeStart,
 867            ReadingEnvelopeBytes,
 868            EnvelopeEnd,
 869            ReadingEndRecord,
 870            End,
 871        }
 872    }
 873
 874    internal class SingletonMessageDecoder : FramingDecoder
 875    {
 876        private IntDecoder _sizeDecoder;
 877        private int _chunkBytesNeeded;
 878        private int _chunkSize;
 879
 880        public SingletonMessageDecoder(ILogger logger) : base(logger)
 881        {
 882            _sizeDecoder = new IntDecoder(logger);
 883            CurrentState = State.ChunkStart;
 884        }
 885
 886        public void Reset()
 887        {
 888            CurrentState = State.ChunkStart;
 889        }
 890
 891        public State CurrentState { get; private set; }
 892
 893        protected override string CurrentStateAsString => CurrentState.ToString();
 894
 895        public int ChunkSize
 896        {
 897            get
 898            {
 899                if (CurrentState < State.ChunkStart)
 900                {
 901                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 902                }
 903
 904                return _chunkSize;
 905            }
 906        }
 907
 908        public override int Decode(ReadOnlySequence<byte> buffer)
 909        {
 910            DecoderHelper.ValidateSize(buffer.Length);
 911            ReadOnlySpan<byte> data = buffer.First.Span;
 912            try
 913            {
 914                int bytesConsumed;
 915                Logger.LogStartState(this);
 916                switch (CurrentState)
 917                {
 918                    case State.ReadingEnvelopeChunkSize:
 919                        bytesConsumed = _sizeDecoder.Decode(buffer);
 920                        if (_sizeDecoder.IsValueDecoded)
 921                        {
 922                            _chunkSize = _sizeDecoder.Value;
 923                            _sizeDecoder.Reset();
 924
 925                            if (_chunkSize == 0)
 926                            {
 927                                CurrentState = State.EnvelopeEnd;
 928                            }
 929                            else
 930                            {
 931                                CurrentState = State.ChunkStart;
 932                                _chunkBytesNeeded = _chunkSize;
 933                            }
 934                        }
 935                        break;
 936                    case State.ChunkStart:
 937                        bytesConsumed = 0;
 938                        CurrentState = State.ReadingEnvelopeBytes;
 939                        break;
 940                    case State.ReadingEnvelopeBytes:
 941                        bytesConsumed = (int)buffer.Length;
 942                        if (bytesConsumed > _chunkBytesNeeded)
 943                        {
 944                            bytesConsumed = _chunkBytesNeeded;
 945                        }
 946                        _chunkBytesNeeded -= bytesConsumed;
 947                        if (_chunkBytesNeeded == 0)
 948                        {
 949                            CurrentState = State.ChunkEnd;
 950                        }
 951                        break;
 952                    case State.ChunkEnd:
 953                        bytesConsumed = 0;
 954                        CurrentState = State.ReadingEnvelopeChunkSize;
 955                        break;
 956                    case State.EnvelopeEnd:
 957                        ValidateRecordType(FramingRecordType.End, (FramingRecordType)data[0]);
 958                        bytesConsumed = 1;
 959                        CurrentState = State.End;
 960                        break;
 961                    case State.End:
 962                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 963                            CreateException(new InvalidDataException(SR.FramingAtEnd)));
 964
 965                    default:
 966                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 967                            CreateException(new InvalidDataException(SR.InvalidDecoderStateMachine)));
 968                }
 969
 970                Logger.LogEndState(this, bytesConsumed);
 971                return bytesConsumed;
 972            }
 973            catch (InvalidDataException e)
 974            {
 975                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
 976            }
 977        }
 978
 979        public enum State
 980        {
 981            ReadingEnvelopeChunkSize,
 982            ChunkStart,
 983            ReadingEnvelopeBytes,
 984            ChunkEnd,
 985            EnvelopeEnd,
 986            End,
 987        }
 988    }
 989
 990    // Pattern:
 991    //   Start,
 992    //   (UpgradeRequest, upgrade-bytes)*,
 993    //   EnvelopeStart,
 994    internal class ServerSingletonDecoder : FramingDecoder
 995    {
 996        private readonly ViaStringDecoder _viaDecoder;
 997        private readonly ContentTypeStringDecoder _contentTypeDecoder;
 998        private string _contentType;
 999        private string _upgrade;
 1000
 1001        public ServerSingletonDecoder(int maxViaLength, int maxContentTypeLength, ILogger logger) : base(logger)
 1002        {
 1003            _viaDecoder = new ViaStringDecoder(maxViaLength, logger);
 1004            _contentTypeDecoder = new ContentTypeStringDecoder(maxContentTypeLength, logger);
 1005            Reset();
 1006        }
 1007
 1008        public void Reset()
 1009        {
 1010            CurrentState = State.ReadingViaRecord;
 1011        }
 1012
 1013        public State CurrentState { get; private set; }
 1014
 1015        protected override string CurrentStateAsString => CurrentState.ToString();
 1016
 1017        public override Uri Via
 1018        {
 1019            get
 1020            {
 1021                if (CurrentState < State.ReadingContentTypeRecord)
 1022                {
 1023                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 1024                }
 1025
 1026                return _viaDecoder.ValueAsUri;
 1027            }
 1028        }
 1029
 1030        public override string ContentType
 1031        {
 1032            get
 1033            {
 1034                if (CurrentState < State.PreUpgradeStart)
 1035                {
 1036                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 1037                }
 1038
 1039                return _contentType;
 1040            }
 1041        }
 1042
 1043        public string Upgrade
 1044        {
 1045            get
 1046            {
 1047                if (CurrentState != State.UpgradeRequest)
 1048                {
 1049                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 1050                }
 1051
 1052                return _upgrade;
 1053            }
 1054        }
 1055
 1056        public override int Decode(ReadOnlySequence<byte> buffer)
 1057        {
 1058            DecoderHelper.ValidateSize(buffer.Length);
 1059            ReadOnlySpan<byte> data = buffer.First.Span;
 1060            try
 1061            {
 1062                int bytesConsumed;
 1063                FramingRecordType recordType;
 1064                Logger.LogStartState(this);
 1065                switch (CurrentState)
 1066                {
 1067                    case State.ReadingViaRecord:
 1068                        recordType = (FramingRecordType)data[0];
 1069                        ValidateRecordType(FramingRecordType.Via, recordType);
 1070                        bytesConsumed = 1;
 1071                        _viaDecoder.Reset();
 1072                        CurrentState = State.ReadingViaString;
 1073                        break;
 1074                    case State.ReadingViaString:
 1075                        bytesConsumed = _viaDecoder.Decode(buffer);
 1076                        if (_viaDecoder.IsValueDecoded)
 1077                        {
 1078                            CurrentState = State.ReadingContentTypeRecord;
 1079                        }
 1080                        break;
 1081                    case State.ReadingContentTypeRecord:
 1082                        recordType = (FramingRecordType)data[0];
 1083                        if (recordType == FramingRecordType.KnownEncoding)
 1084                        {
 1085                            bytesConsumed = 1;
 1086                            CurrentState = State.ReadingContentTypeByte;
 1087                        }
 1088                        else
 1089                        {
 1090                            ValidateRecordType(FramingRecordType.ExtensibleEncoding, recordType);
 1091                            bytesConsumed = 1;
 1092                            _contentTypeDecoder.Reset();
 1093                            CurrentState = State.ReadingContentTypeString;
 1094                        }
 1095                        break;
 1096                    case State.ReadingContentTypeByte:
 1097                        _contentType = ContentTypeStringDecoder.GetString((FramingEncodingType)data[0]);
 1098                        bytesConsumed = 1;
 1099                        CurrentState = State.PreUpgradeStart;
 1100                        break;
 1101                    case State.ReadingContentTypeString:
 1102                        bytesConsumed = _contentTypeDecoder.Decode(buffer);
 1103                        if (_contentTypeDecoder.IsValueDecoded)
 1104                        {
 1105                            CurrentState = State.PreUpgradeStart;
 1106                            _contentType = _contentTypeDecoder.Value;
 1107                        }
 1108                        break;
 1109                    case State.PreUpgradeStart:
 1110                        bytesConsumed = 0;
 1111                        CurrentState = State.ReadingUpgradeRecord;
 1112                        break;
 1113                    case State.ReadingUpgradeRecord:
 1114                        recordType = (FramingRecordType)data[0];
 1115                        if (recordType == FramingRecordType.UpgradeRequest)
 1116                        {
 1117                            bytesConsumed = 1;
 1118                            _contentTypeDecoder.Reset();
 1119                            CurrentState = State.ReadingUpgradeString;
 1120                        }
 1121                        else
 1122                        {
 1123                            bytesConsumed = 0;
 1124                            CurrentState = State.ReadingPreambleEndRecord;
 1125                        }
 1126                        break;
 1127                    case State.ReadingUpgradeString:
 1128                        bytesConsumed = _contentTypeDecoder.Decode(buffer);
 1129                        if (_contentTypeDecoder.IsValueDecoded)
 1130                        {
 1131                            CurrentState = State.UpgradeRequest;
 1132                            _upgrade = _contentTypeDecoder.Value;
 1133                        }
 1134                        break;
 1135                    case State.UpgradeRequest:
 1136                        bytesConsumed = 0;
 1137                        CurrentState = State.ReadingUpgradeRecord;
 1138                        break;
 1139                    case State.ReadingPreambleEndRecord:
 1140                        recordType = (FramingRecordType)data[0];
 1141                        ValidateRecordType(FramingRecordType.PreambleEnd, recordType);
 1142                        bytesConsumed = 1;
 1143                        CurrentState = State.Start;
 1144                        break;
 1145                    case State.Start:
 1146                        bytesConsumed = 0;
 1147                        CurrentState = State.ReadingEnvelopeRecord;
 1148                        break;
 1149                    case State.ReadingEnvelopeRecord:
 1150                        ValidateRecordType(FramingRecordType.UnsizedEnvelope, (FramingRecordType)data[0]);
 1151                        bytesConsumed = 1;
 1152                        CurrentState = State.EnvelopeStart;
 1153                        break;
 1154                    case State.EnvelopeStart:
 1155                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 1156                            CreateException(new InvalidDataException(SR.FramingAtEnd)));
 1157                    default:
 1158                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 1159                            CreateException(new InvalidDataException(SR.InvalidDecoderStateMachine)));
 1160                }
 1161
 1162                Logger.LogEndState(this, bytesConsumed);
 1163                return bytesConsumed;
 1164            }
 1165            catch (InvalidDataException e)
 1166            {
 1167                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
 1168            }
 1169        }
 1170
 1171        public enum State
 1172        {
 1173            ReadingViaRecord,
 1174            ReadingViaString,
 1175            ReadingContentTypeRecord,
 1176            ReadingContentTypeString,
 1177            ReadingContentTypeByte,
 1178            PreUpgradeStart,
 1179            ReadingUpgradeRecord,
 1180            ReadingUpgradeString,
 1181            UpgradeRequest,
 1182            ReadingPreambleEndRecord,
 1183            Start,
 1184            ReadingEnvelopeRecord,
 1185            EnvelopeStart,
 1186            ReadingEnvelopeChunkSize,
 1187            ChunkStart,
 1188            ReadingEnvelopeChunk,
 1189            ChunkEnd,
 1190            End,
 1191        }
 1192    }
 1193
 1194    // Pattern:
 1195    //   Start,
 1196    //   EnvelopeStart,
 1197    internal class ServerSingletonSizedDecoder : FramingDecoder
 1198    {
 1199        private readonly ViaStringDecoder _viaDecoder;
 1200        private readonly ContentTypeStringDecoder _contentTypeDecoder;
 1201        private string _contentType;
 1202
 1203        public ServerSingletonSizedDecoder(int maxViaLength, int maxContentTypeLength, ILogger logger) : base(logger)
 1204        {
 1205            _viaDecoder = new ViaStringDecoder(maxViaLength, logger);
 1206            _contentTypeDecoder = new ContentTypeStringDecoder(maxContentTypeLength, logger);
 1207            CurrentState = State.ReadingViaRecord;
 1208        }
 1209
 1210        public override int Decode(ReadOnlySequence<byte> buffer)
 1211        {
 1212            DecoderHelper.ValidateSize(buffer.Length);
 1213            ReadOnlySpan<byte> data = buffer.First.Span;
 1214            try
 1215            {
 1216                int bytesConsumed;
 1217                FramingRecordType recordType;
 1218                Logger.LogStartState(this);
 1219                switch (CurrentState)
 1220                {
 1221                    case State.ReadingViaRecord:
 1222                        recordType = (FramingRecordType)data[0];
 1223                        ValidateRecordType(FramingRecordType.Via, recordType);
 1224                        bytesConsumed = 1;
 1225                        _viaDecoder.Reset();
 1226                        CurrentState = State.ReadingViaString;
 1227                        break;
 1228                    case State.ReadingViaString:
 1229                        bytesConsumed = _viaDecoder.Decode(buffer);
 1230                        if (_viaDecoder.IsValueDecoded)
 1231                        {
 1232                            CurrentState = State.ReadingContentTypeRecord;
 1233                        }
 1234
 1235                        break;
 1236                    case State.ReadingContentTypeRecord:
 1237                        recordType = (FramingRecordType)data[0];
 1238                        if (recordType == FramingRecordType.KnownEncoding)
 1239                        {
 1240                            bytesConsumed = 1;
 1241                            CurrentState = State.ReadingContentTypeByte;
 1242                        }
 1243                        else
 1244                        {
 1245                            ValidateRecordType(FramingRecordType.ExtensibleEncoding, recordType);
 1246                            bytesConsumed = 1;
 1247                            _contentTypeDecoder.Reset();
 1248                            CurrentState = State.ReadingContentTypeString;
 1249                        }
 1250                        break;
 1251                    case State.ReadingContentTypeByte:
 1252                        _contentType = ContentTypeStringDecoder.GetString((FramingEncodingType)data[0]);
 1253                        bytesConsumed = 1;
 1254                        CurrentState = State.Start;
 1255                        break;
 1256                    case State.ReadingContentTypeString:
 1257                        bytesConsumed = _contentTypeDecoder.Decode(buffer);
 1258                        if (_contentTypeDecoder.IsValueDecoded)
 1259                        {
 1260                            CurrentState = State.Start;
 1261                            _contentType = _contentTypeDecoder.Value;
 1262                        }
 1263                        break;
 1264                    case State.Start:
 1265                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 1266                            CreateException(new InvalidDataException(SR.FramingAtEnd)));
 1267                    default:
 1268                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 1269                            CreateException(new InvalidDataException(SR.InvalidDecoderStateMachine)));
 1270                }
 1271
 1272                Logger.LogEndState(this, bytesConsumed);
 1273                return bytesConsumed;
 1274            }
 1275            catch (InvalidDataException e)
 1276            {
 1277                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
 1278            }
 1279        }
 1280
 1281        public void Reset(long streamPosition)
 1282        {
 1283            CurrentState = State.ReadingViaRecord;
 1284        }
 1285
 1286        public State CurrentState { get; private set; }
 1287
 1288        protected override string CurrentStateAsString => CurrentState.ToString();
 1289
 1290        public override Uri Via
 1291        {
 1292            get
 1293            {
 1294                if (CurrentState < State.ReadingContentTypeRecord)
 1295                {
 1296                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 1297                }
 1298
 1299                return _viaDecoder.ValueAsUri;
 1300            }
 1301        }
 1302
 1303        public override string ContentType
 1304        {
 1305            get
 1306            {
 1307                if (CurrentState < State.Start)
 1308                {
 1309                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.FramingVa
 1310                }
 1311
 1312                return _contentType;
 1313            }
 1314        }
 1315
 1316        public enum State
 1317        {
 1318            ReadingViaRecord,
 1319            ReadingViaString,
 1320            ReadingContentTypeRecord,
 1321            ReadingContentTypeString,
 1322            ReadingContentTypeByte,
 1323            Start,
 1324        }
 1325    }
 1326}