< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.MessagePatterns
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Channels/BinaryMessageEncoderFactory.cs
Line coverage
56%
Covered lines: 158
Uncovered lines: 123
Coverable lines: 281
Total lines: 1772
Line coverage: 56.2%
Branch coverage
34%
Covered branches: 28
Total branches: 82
Branch coverage: 34.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
.ctor(...)100%11100%
TryCreateMessage(...)60.71%282879.51%
TryLookupKey(...)50%2266.66%
.ctor(...)83.33%6694.44%
.ctor(...)0%10100%
GetBufferedReaderAtBody()100%110%
OnBodyToString(...)0%220%
OnClose()11.11%181840%
OnCreateBufferedCopy(...)100%110%
OnGetReaderAtBodyContents()100%11100%
OnGetBodyAttribute(...)100%110%
.ctor(...)0%440%
Close()0%220%
CreateMessage()0%220%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Channels/BinaryMessageEncoderFactory.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.Collections.Generic;
 6using System.IO;
 7using System.Text;
 8using System.Threading.Tasks;
 9using System.Xml;
 10using CoreWCF.Runtime;
 11using CoreWCF.Xml;
 12
 13namespace CoreWCF.Channels
 14{
 15    internal class BinaryMessageEncoderFactory : MessageEncoderFactory
 16    {
 17        private const int maxPooledXmlReaderPerMessage = 2;
 18        private readonly BinaryMessageEncoder _messageEncoder;
 19        private readonly MessageVersion _messageVersion;
 20
 21        // Double-checked locking pattern requires volatile for read/write synchronization
 22        //volatile SynchronizedPool<XmlDictionaryWriter> streamedWriterPool;
 23        //volatile SynchronizedPool<XmlDictionaryReader> streamedReaderPool;
 24        private volatile SynchronizedPool<BinaryBufferedMessageData> _bufferedDataPool;
 25        private volatile SynchronizedPool<BinaryBufferedMessageWriter> _bufferedWriterPool;
 26        private volatile SynchronizedPool<RecycledMessageState> _recycledStatePool;
 27        private readonly OnXmlDictionaryReaderClose _onStreamedReaderClose;
 28        private readonly XmlDictionaryReaderQuotas _bufferedReadReaderQuotas;
 29        private readonly BinaryVersion _binaryVersion;
 30
 31        public BinaryMessageEncoderFactory(MessageVersion messageVersion, int maxReadPoolSize, int maxWritePoolSize, int
 32            XmlDictionaryReaderQuotas readerQuotas, long maxReceivedMessageSize, BinaryVersion version, CompressionForma
 33        {
 34            _messageVersion = messageVersion;
 35            MaxReadPoolSize = maxReadPoolSize;
 36            MaxWritePoolSize = maxWritePoolSize;
 37            MaxSessionSize = maxSessionSize;
 38            ThisLock = new object();
 39            _onStreamedReaderClose = new OnXmlDictionaryReaderClose(ReturnStreamedReader);
 40            ReaderQuotas = new XmlDictionaryReaderQuotas();
 41            if (readerQuotas != null)
 42            {
 43                readerQuotas.CopyTo(ReaderQuotas);
 44            }
 45
 46            _bufferedReadReaderQuotas = EncoderHelpers.GetBufferedReadQuotas(ReaderQuotas);
 47            MaxReceivedMessageSize = maxReceivedMessageSize;
 48
 49            _binaryVersion = version;
 50            CompressionFormat = compressionFormat;
 51            _messageEncoder = new BinaryMessageEncoder(this, false, 0);
 52        }
 53
 54        public static IXmlDictionary XmlDictionary
 55        {
 56            get { return XD.Dictionary; }
 57        }
 58
 59        public override MessageEncoder Encoder
 60        {
 61            get
 62            {
 63                return _messageEncoder;
 64            }
 65        }
 66
 67        public override MessageVersion MessageVersion
 68        {
 69            get { return _messageVersion; }
 70        }
 71
 72        public int MaxWritePoolSize { get; }
 73
 74        public XmlDictionaryReaderQuotas ReaderQuotas { get; }
 75
 76        public int MaxReadPoolSize { get; }
 77
 78        public int MaxSessionSize { get; }
 79
 80        public CompressionFormat CompressionFormat { get; }
 81
 82        private long MaxReceivedMessageSize
 83        {
 84            get;
 85            set;
 86        }
 87
 88        private object ThisLock { get; }
 89
 90        private SynchronizedPool<RecycledMessageState> RecycledStatePool
 91        {
 92            get
 93            {
 94                if (_recycledStatePool == null)
 95                {
 96                    lock (ThisLock)
 97                    {
 98                        if (_recycledStatePool == null)
 99                        {
 100                            //running = true;
 101                            _recycledStatePool = new SynchronizedPool<RecycledMessageState>(MaxReadPoolSize);
 102                        }
 103                    }
 104                }
 105                return _recycledStatePool;
 106            }
 107        }
 108
 109        public override MessageEncoder CreateSessionEncoder()
 110        {
 111            return new BinaryMessageEncoder(this, true, MaxSessionSize);
 112        }
 113
 114        private XmlDictionaryWriter TakeStreamedWriter(Stream stream)
 115        {
 116            return XmlDictionaryWriter.CreateBinaryWriter(stream, _binaryVersion.Dictionary, null, false);
 117            // TODO: Revert once IXmlBinaryWriterInitializer is available
 118            //if (streamedWriterPool == null)
 119            //{
 120            //    lock (ThisLock)
 121            //    {
 122            //        if (streamedWriterPool == null)
 123            //        {
 124            //            //running = true;
 125            //            streamedWriterPool = new SynchronizedPool<XmlDictionaryWriter>(maxWritePoolSize);
 126            //        }
 127            //    }
 128            //}
 129            //XmlDictionaryWriter xmlWriter = streamedWriterPool.Take();
 130            //if (xmlWriter == null)
 131            //{
 132            //    xmlWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, binaryVersion.Dictionary, null, false);
 133            //}
 134            //else
 135            //{
 136            //    ((IXmlBinaryWriterInitializer)xmlWriter).SetOutput(stream, binaryVersion.Dictionary, null, false);
 137            //}
 138            //return xmlWriter;
 139        }
 140
 141        private void ReturnStreamedWriter(XmlDictionaryWriter xmlWriter)
 142        {
 143            xmlWriter.Dispose();
 144            //streamedWriterPool.Return(xmlWriter);
 145        }
 146
 147        private BinaryBufferedMessageWriter TakeBufferedWriter()
 148        {
 149            if (_bufferedWriterPool == null)
 150            {
 151                lock (ThisLock)
 152                {
 153                    if (_bufferedWriterPool == null)
 154                    {
 155                        //running = true;
 156                        _bufferedWriterPool = new SynchronizedPool<BinaryBufferedMessageWriter>(MaxWritePoolSize);
 157                    }
 158                }
 159            }
 160
 161            BinaryBufferedMessageWriter messageWriter = _bufferedWriterPool.Take();
 162            if (messageWriter == null)
 163            {
 164                messageWriter = new BinaryBufferedMessageWriter(_binaryVersion.Dictionary);
 165            }
 166            return messageWriter;
 167        }
 168
 169        private void ReturnMessageWriter(BinaryBufferedMessageWriter messageWriter)
 170        {
 171            _bufferedWriterPool.Return(messageWriter);
 172        }
 173
 174        private XmlDictionaryReader TakeStreamedReader(Stream stream)
 175        {
 176            return XmlDictionaryReader.CreateBinaryReader(stream,
 177                _binaryVersion.Dictionary,
 178                ReaderQuotas,
 179                null);
 180            // TODO: Revert once IXmlBinaryReaderInitializer is available
 181            //if (streamedReaderPool == null)
 182            //{
 183            //    lock (ThisLock)
 184            //    {
 185            //        if (streamedReaderPool == null)
 186            //        {
 187            //            //running = true;
 188            //            streamedReaderPool = new SynchronizedPool<XmlDictionaryReader>(maxReadPoolSize);
 189            //        }
 190            //    }
 191            //}
 192
 193            //XmlDictionaryReader xmlReader = streamedReaderPool.Take();
 194            //if (xmlReader == null)
 195            //{
 196            //    xmlReader = XmlDictionaryReader.CreateBinaryReader(stream,
 197            //        binaryVersion.Dictionary,
 198            //        readerQuotas,
 199            //        null,
 200            //        onStreamedReaderClose);
 201            //    if (TD.ReadPoolMissIsEnabled())
 202            //    {
 203            //        TD.ReadPoolMiss(xmlReader.GetType().Name);
 204            //    }
 205            //}
 206            //else
 207            //{
 208            //    ((IXmlBinaryReaderInitializer)xmlReader).SetInput(stream,
 209            //        binaryVersion.Dictionary,
 210            //        readerQuotas,
 211            //        null,
 212            //        onStreamedReaderClose);
 213            //}
 214
 215            //return xmlReader;
 216        }
 217
 218        private void ReturnStreamedReader(XmlDictionaryReader xmlReader)
 219        {
 220            //streamedReaderPool.Return(xmlReader);
 221        }
 222
 223        private BinaryBufferedMessageData TakeBufferedData(BinaryMessageEncoder messageEncoder)
 224        {
 225            if (_bufferedDataPool == null)
 226            {
 227                lock (ThisLock)
 228                {
 229                    if (_bufferedDataPool == null)
 230                    {
 231                        //running = true;
 232                        _bufferedDataPool = new SynchronizedPool<BinaryBufferedMessageData>(MaxReadPoolSize);
 233                    }
 234                }
 235            }
 236            BinaryBufferedMessageData messageData = _bufferedDataPool.Take();
 237            if (messageData == null)
 238            {
 239                messageData = new BinaryBufferedMessageData(this, maxPooledXmlReaderPerMessage);
 240            }
 241            messageData.SetMessageEncoder(messageEncoder);
 242            return messageData;
 243        }
 244
 245        private void ReturnBufferedData(BinaryBufferedMessageData messageData)
 246        {
 247            messageData.SetMessageEncoder(null);
 248            _bufferedDataPool.Return(messageData);
 249        }
 250
 251        private class BinaryBufferedMessageData : BufferedMessageData
 252        {
 253            private readonly BinaryMessageEncoderFactory _factory;
 254            private BinaryMessageEncoder _messageEncoder;
 255            private readonly Pool<XmlDictionaryReader> _readerPool;
 256            private readonly OnXmlDictionaryReaderClose _onClose;
 257
 258            public BinaryBufferedMessageData(BinaryMessageEncoderFactory factory, int maxPoolSize)
 259                : base(factory.RecycledStatePool)
 260            {
 261                _factory = factory;
 262                _readerPool = new Pool<XmlDictionaryReader>(maxPoolSize);
 263                _onClose = new OnXmlDictionaryReaderClose(OnXmlReaderClosed);
 264            }
 265
 266            public override MessageEncoder MessageEncoder
 267            {
 268                get { return _messageEncoder; }
 269            }
 270
 271            public override XmlDictionaryReaderQuotas Quotas
 272            {
 273                get { return _factory.ReaderQuotas; }
 274            }
 275
 276            public void SetMessageEncoder(BinaryMessageEncoder messageEncoder)
 277            {
 278                _messageEncoder = messageEncoder;
 279            }
 280
 281            protected override XmlDictionaryReader TakeXmlReader()
 282            {
 283                ArraySegment<byte> buffer = Buffer;
 284
 285                return XmlDictionaryReader.CreateBinaryReader(buffer.Array, buffer.Offset, buffer.Count,
 286                                        _factory._binaryVersion.Dictionary,
 287                                        _factory._bufferedReadReaderQuotas,
 288                                        _messageEncoder.ReaderSession);
 289                // TODO: Revert once IXmlBinaryReaderInitializer is available
 290                //ArraySegment<byte> buffer = this.Buffer;
 291                //XmlDictionaryReader xmlReader = readerPool.Take();
 292
 293                //if (xmlReader != null)
 294                //{
 295                //    ((IXmlBinaryReaderInitializer)xmlReader).SetInput(buffer.Array, buffer.Offset, buffer.Count,
 296                //        factory.binaryVersion.Dictionary,
 297                //        factory.bufferedReadReaderQuotas,
 298                //        messageEncoder.ReaderSession,
 299                //        onClose);
 300                //}
 301                //else
 302                //{
 303                //    xmlReader = XmlDictionaryReader.CreateBinaryReader(buffer.Array, buffer.Offset, buffer.Count,
 304                //        factory.binaryVersion.Dictionary,
 305                //        factory.bufferedReadReaderQuotas,
 306                //        messageEncoder.ReaderSession,
 307                //        onClose);
 308                //    if (TD.ReadPoolMissIsEnabled())
 309                //    {
 310                //        TD.ReadPoolMiss(xmlReader.GetType().Name);
 311                //    }
 312                //}
 313
 314                //return xmlReader;
 315            }
 316
 317            protected override void ReturnXmlReader(XmlDictionaryReader reader)
 318            {
 319                _readerPool.Return(reader);
 320            }
 321
 322            protected override void OnClosed()
 323            {
 324                _factory.ReturnBufferedData(this);
 325            }
 326        }
 327
 328        private class BinaryBufferedMessageWriter : BufferedMessageWriter
 329        {
 330            private XmlDictionaryWriter _writer;
 331            private readonly IXmlDictionary _dictionary;
 332            private readonly XmlBinaryWriterSession _session;
 333
 334            public BinaryBufferedMessageWriter(IXmlDictionary dictionary)
 335            {
 336                _dictionary = dictionary;
 337            }
 338
 339            public BinaryBufferedMessageWriter(IXmlDictionary dictionary, XmlBinaryWriterSession session)
 340            {
 341                _dictionary = dictionary;
 342                _session = session;
 343            }
 344
 345            protected override XmlDictionaryWriter TakeXmlWriter(Stream stream)
 346            {
 347                return XmlDictionaryWriter.CreateBinaryWriter(stream, _dictionary, _session, false);
 348                // TODO: Revert once IXmlBinaryReaderInitializer is available
 349                //XmlDictionaryWriter returnedWriter = writer;
 350                //if (returnedWriter == null)
 351                //{
 352                //    returnedWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary, session, false);
 353                //}
 354                //else
 355                //{
 356                //    writer = null;
 357                //    ((IXmlBinaryWriterInitializer)returnedWriter).SetOutput(stream, dictionary, session, false);
 358                //}
 359                //return returnedWriter;
 360            }
 361
 362            protected override void ReturnXmlWriter(XmlDictionaryWriter writer)
 363            {
 364                writer.Dispose();
 365
 366                if (_writer == null)
 367                {
 368                    _writer = writer;
 369                }
 370            }
 371        }
 372
 373        private class BinaryMessageEncoder : MessageEncoder, ICompressedMessageEncoder
 374        {
 375            private const string SupportedCompressionTypesMessageProperty = "BinaryMessageEncoder.SupportedCompressionTy
 376            private readonly BinaryMessageEncoderFactory _factory;
 377            private readonly bool _isSession;
 378            private XmlBinaryWriterSessionWithQuota _writerSession;
 379            private BinaryBufferedMessageWriter _sessionMessageWriter;
 380
 381            //XmlBinaryReaderSession readerSessionForLogging;
 382            //bool readerSessionForLoggingIsInvalid = false;
 383            //int writeIdCounter;
 384            private int _idCounter;
 385            private readonly int _maxSessionSize;
 386            private int _remainingReaderSessionSize;
 387            private bool _isReaderSessionInvalid;
 388            private MessagePatterns _messagePatterns;
 389            private readonly string _contentType;
 390            private readonly string _normalContentType;
 391            private readonly string _gzipCompressedContentType;
 392            private readonly string _deflateCompressedContentType;
 393            private CompressionFormat _sessionCompressionFormat;
 394            private readonly long _maxReceivedMessageSize;
 395
 396            public BinaryMessageEncoder(BinaryMessageEncoderFactory factory, bool isSession, int maxSessionSize)
 397            {
 398                _factory = factory;
 399                _isSession = isSession;
 400                _maxSessionSize = maxSessionSize;
 401                _remainingReaderSessionSize = maxSessionSize;
 402                _normalContentType = isSession ? factory._binaryVersion.SessionContentType : factory._binaryVersion.Cont
 403                _gzipCompressedContentType = isSession ? BinaryVersion.GZipVersion1.SessionContentType : BinaryVersion.G
 404                _deflateCompressedContentType = isSession ? BinaryVersion.DeflateVersion1.SessionContentType : BinaryVer
 405                _sessionCompressionFormat = _factory.CompressionFormat;
 406                _maxReceivedMessageSize = _factory.MaxReceivedMessageSize;
 407
 408                switch (_factory.CompressionFormat)
 409                {
 410                    case CompressionFormat.Deflate:
 411                        _contentType = _deflateCompressedContentType;
 412                        break;
 413                    case CompressionFormat.GZip:
 414                        _contentType = _gzipCompressedContentType;
 415                        break;
 416                    default:
 417                        _contentType = _normalContentType;
 418                        break;
 419                }
 420            }
 421
 422            public override string ContentType
 423            {
 424                get
 425                {
 426                    return _contentType;
 427                }
 428            }
 429
 430            public override MessageVersion MessageVersion
 431            {
 432                get { return _factory._messageVersion; }
 433            }
 434
 435            public override string MediaType
 436            {
 437                get { return _contentType; }
 438            }
 439
 440            public XmlBinaryReaderSession ReaderSession { get; private set; }
 441
 442            public bool CompressionEnabled
 443            {
 444                get { return _factory.CompressionFormat != CompressionFormat.None; }
 445            }
 446
 447            private ArraySegment<byte> AddSessionInformationToMessage(ArraySegment<byte> messageData, BufferManager buff
 448            {
 449                int dictionarySize = 0;
 450                byte[] buffer = messageData.Array;
 451
 452                if (_writerSession.HasNewStrings)
 453                {
 454                    IList<XmlDictionaryString> newStrings = _writerSession.GetNewStrings();
 455                    for (int i = 0; i < newStrings.Count; i++)
 456                    {
 457                        int utf8ValueSize = Encoding.UTF8.GetByteCount(newStrings[i].Value);
 458                        dictionarySize += IntEncoder.GetEncodedSize(utf8ValueSize) + utf8ValueSize;
 459                    }
 460
 461                    int messageSize = messageData.Offset + messageData.Count;
 462                    int remainingMessageSize = maxMessageSize - messageSize;
 463                    if (remainingMessageSize - dictionarySize < 0)
 464                    {
 465                        string excMsg = SR.Format(SRCommon.MaxSentMessageSizeExceeded, maxMessageSize);
 466                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(excMsg));
 467                    }
 468
 469                    int requiredBufferSize = messageData.Offset + messageData.Count + dictionarySize;
 470                    if (buffer.Length < requiredBufferSize)
 471                    {
 472                        byte[] newBuffer = bufferManager.TakeBuffer(requiredBufferSize);
 473                        Buffer.BlockCopy(buffer, messageData.Offset, newBuffer, messageData.Offset, messageData.Count);
 474                        bufferManager.ReturnBuffer(buffer);
 475                        buffer = newBuffer;
 476                    }
 477
 478                    Buffer.BlockCopy(buffer, messageData.Offset, buffer, messageData.Offset + dictionarySize, messageDat
 479
 480                    int offset = messageData.Offset;
 481                    for (int i = 0; i < newStrings.Count; i++)
 482                    {
 483                        string newString = newStrings[i].Value;
 484                        int utf8ValueSize = Encoding.UTF8.GetByteCount(newString);
 485                        offset += IntEncoder.Encode(utf8ValueSize, buffer, offset);
 486                        offset += Encoding.UTF8.GetBytes(newString, 0, newString.Length, buffer, offset);
 487                    }
 488
 489                    _writerSession.ClearNewStrings();
 490                }
 491
 492                int headerSize = IntEncoder.GetEncodedSize(dictionarySize);
 493                int newOffset = messageData.Offset - headerSize;
 494                int newSize = headerSize + messageData.Count + dictionarySize;
 495                IntEncoder.Encode(dictionarySize, buffer, newOffset);
 496                return new ArraySegment<byte>(buffer, newOffset, newSize);
 497            }
 498
 499            private ArraySegment<byte> ExtractSessionInformationFromMessage(ArraySegment<byte> messageData)
 500            {
 501                if (_isReaderSessionInvalid)
 502                {
 503                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.BinaryEncoderS
 504                }
 505
 506                byte[] buffer = messageData.Array;
 507                int dictionarySize;
 508                int headerSize;
 509                int newOffset;
 510                int newSize;
 511                bool throwing = true;
 512                try
 513                {
 514                    IntDecoder decoder = new IntDecoder();
 515                    headerSize = decoder.Decode(buffer, messageData.Offset, messageData.Count);
 516                    dictionarySize = decoder.Value;
 517                    if (dictionarySize > messageData.Count)
 518                    {
 519                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.BinaryEnco
 520                    }
 521                    newOffset = messageData.Offset + headerSize + dictionarySize;
 522                    newSize = messageData.Count - headerSize - dictionarySize;
 523                    if (newSize < 0)
 524                    {
 525                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.BinaryEnco
 526                    }
 527                    if (dictionarySize > 0)
 528                    {
 529                        if (dictionarySize > _remainingReaderSessionSize)
 530                        {
 531                            string message = SR.Format(SR.BinaryEncoderSessionTooLarge, _maxSessionSize);
 532                            Exception inner = new QuotaExceededException(message);
 533                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message
 534                        }
 535                        else
 536                        {
 537                            _remainingReaderSessionSize -= dictionarySize;
 538                        }
 539
 540                        int size = dictionarySize;
 541                        int offset = messageData.Offset + headerSize;
 542
 543                        while (size > 0)
 544                        {
 545                            decoder.Reset();
 546                            int bytesDecoded = decoder.Decode(buffer, offset, size);
 547                            int utf8ValueSize = decoder.Value;
 548                            offset += bytesDecoded;
 549                            size -= bytesDecoded;
 550                            if (utf8ValueSize > size)
 551                            {
 552                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.Bi
 553                            }
 554                            string value = Encoding.UTF8.GetString(buffer, offset, utf8ValueSize);
 555                            offset += utf8ValueSize;
 556                            size -= utf8ValueSize;
 557                            ReaderSession.Add(_idCounter, value);
 558                            _idCounter++;
 559                        }
 560                    }
 561                    throwing = false;
 562                }
 563                finally
 564                {
 565                    if (throwing)
 566                    {
 567                        _isReaderSessionInvalid = true;
 568                    }
 569                }
 570
 571                return new ArraySegment<byte>(buffer, newOffset, newSize);
 572            }
 573
 574            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentTy
 575            {
 576                if (bufferManager == null)
 577                {
 578                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(bufferManager));
 579                }
 580
 581                CompressionFormat compressionFormat = CheckContentType(contentType);
 582
 583                if (compressionFormat != CompressionFormat.None)
 584                {
 585                    MessageEncoderCompressionHandler.DecompressBuffer(ref buffer, bufferManager, compressionFormat, _max
 586                }
 587
 588                if (_isSession)
 589                {
 590                    if (ReaderSession == null)
 591                    {
 592                        ReaderSession = new XmlBinaryReaderSession();
 593                        _messagePatterns = new MessagePatterns(_factory._binaryVersion.Dictionary, ReaderSession, Messag
 594                    }
 595                    try
 596                    {
 597                        buffer = ExtractSessionInformationFromMessage(buffer);
 598                    }
 599                    catch (InvalidDataException)
 600                    {
 601                        //MessageLogger.LogMessage(buffer, MessageLoggingSource.Malformed);
 602                        throw;
 603                    }
 604                }
 605                BinaryBufferedMessageData messageData = _factory.TakeBufferedData(this);
 606                Message message;
 607                if (_messagePatterns != null)
 608                {
 609                    message = _messagePatterns.TryCreateMessage(buffer.Array, buffer.Offset, buffer.Count, bufferManager
 610                }
 611                else
 612                {
 613                    message = null;
 614                }
 615                if (message == null)
 616                {
 617                    messageData.Open(buffer, bufferManager);
 618                    RecycledMessageState messageState = messageData.TakeMessageState();
 619                    if (messageState == null)
 620                    {
 621                        messageState = new RecycledMessageState();
 622                    }
 623                    message = new BufferedMessage(messageData, messageState);
 624                }
 625                message.Properties.Encoder = this;
 626
 627                return message;
 628            }
 629
 630            public override Task<Message> ReadMessageAsync(Stream stream, int maxSizeOfHeaders, string contentType)
 631            {
 632                if (stream == null)
 633                {
 634                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(stream));
 635                }
 636
 637                CompressionFormat compressionFormat = CheckContentType(contentType);
 638
 639                if (compressionFormat != CompressionFormat.None)
 640                {
 641                    stream = new MaxMessageSizeStream(
 642                        MessageEncoderCompressionHandler.GetDecompressStream(stream, compressionFormat), _maxReceivedMes
 643                }
 644
 645                XmlDictionaryReader reader = _factory.TakeStreamedReader(stream);
 646                Message message = Message.CreateMessage(reader, maxSizeOfHeaders, _factory._messageVersion);
 647                message.Properties.Encoder = this;
 648
 649                return Task.FromResult(message);
 650            }
 651
 652            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferMan
 653            {
 654                if (message == null)
 655                {
 656                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(message));
 657                }
 658
 659                if (bufferManager == null)
 660                {
 661                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(bufferManager));
 662                }
 663
 664                if (maxMessageSize < 0)
 665                {
 666                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(max
 667                        SRCommon.ValueMustBeNonNegative));
 668                }
 669
 670                message.Properties.Encoder = this;
 671
 672                if (_isSession)
 673                {
 674                    if (_writerSession == null)
 675                    {
 676                        _writerSession = new XmlBinaryWriterSessionWithQuota(_maxSessionSize);
 677                        _sessionMessageWriter = new BinaryBufferedMessageWriter(_factory._binaryVersion.Dictionary, _wri
 678                    }
 679                    messageOffset += IntEncoder.MaxEncodedSize;
 680                }
 681
 682                if (messageOffset < 0)
 683                {
 684                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(mes
 685                        SRCommon.ValueMustBeNonNegative));
 686                }
 687
 688                if (messageOffset > maxMessageSize)
 689                {
 690                    string excMsg = SR.Format(SRCommon.MaxSentMessageSizeExceeded, maxMessageSize);
 691
 692                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(excMsg));
 693                }
 694
 695                ThrowIfMismatchedMessageVersion(message);
 696                BinaryBufferedMessageWriter messageWriter;
 697                if (_isSession)
 698                {
 699                    messageWriter = _sessionMessageWriter;
 700                }
 701                else
 702                {
 703                    messageWriter = _factory.TakeBufferedWriter();
 704                }
 705                ArraySegment<byte> messageData = messageWriter.WriteMessage(message, bufferManager, messageOffset, maxMe
 706
 707                //this.readerSessionForLoggingIsInvalid = true;
 708
 709                if (_isSession)
 710                {
 711                    messageData = AddSessionInformationToMessage(messageData, bufferManager, maxMessageSize);
 712                }
 713                else
 714                {
 715                    _factory.ReturnMessageWriter(messageWriter);
 716                }
 717
 718                CompressionFormat compressionFormat = CheckCompressedWrite(message);
 719                if (compressionFormat != CompressionFormat.None)
 720                {
 721                    MessageEncoderCompressionHandler.CompressBuffer(ref messageData, bufferManager, compressionFormat);
 722                }
 723
 724                return messageData;
 725            }
 726
 727            public override async Task WriteMessageAsync(Message message, Stream stream)
 728            {
 729                if (message == null)
 730                {
 731                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(message))
 732                }
 733                if (stream == null)
 734                {
 735                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(stream)))
 736                }
 737
 738                CompressionFormat compressionFormat = CheckCompressedWrite(message);
 739                if (compressionFormat != CompressionFormat.None)
 740                {
 741                    stream = MessageEncoderCompressionHandler.GetCompressStream(stream, compressionFormat);
 742                }
 743
 744                ThrowIfMismatchedMessageVersion(message);
 745                message.Properties.Encoder = this;
 746                XmlDictionaryWriter xmlWriter = _factory.TakeStreamedWriter(stream);
 747                await message.WriteMessageAsync(xmlWriter);
 748                xmlWriter.Flush();
 749
 750                _factory.ReturnStreamedWriter(xmlWriter);
 751                if (compressionFormat != CompressionFormat.None)
 752                {
 753                    stream.Dispose();
 754                }
 755            }
 756
 757            public override bool IsContentTypeSupported(string contentType)
 758            {
 759                bool supported = true;
 760                if (!base.IsContentTypeSupported(contentType))
 761                {
 762                    if (CompressionEnabled)
 763                    {
 764                        supported = (_factory.CompressionFormat == CompressionFormat.GZip &&
 765                            IsContentTypeSupported(contentType, _gzipCompressedContentType, _gzipCompressedContentType))
 766                            (_factory.CompressionFormat == CompressionFormat.Deflate &&
 767                            IsContentTypeSupported(contentType, _deflateCompressedContentType, _deflateCompressedContent
 768                            IsContentTypeSupported(contentType, _normalContentType, _normalContentType);
 769                    }
 770                    else
 771                    {
 772                        supported = false;
 773                    }
 774                }
 775                return supported;
 776            }
 777
 778            public void SetSessionContentType(string contentType)
 779            {
 780                if (IsContentTypeSupported(contentType, _gzipCompressedContentType, _gzipCompressedContentType))
 781                {
 782                    _sessionCompressionFormat = CompressionFormat.GZip;
 783                }
 784                else if (IsContentTypeSupported(contentType, _deflateCompressedContentType, _deflateCompressedContentTyp
 785                {
 786                    _sessionCompressionFormat = CompressionFormat.Deflate;
 787                }
 788                else
 789                {
 790                    _sessionCompressionFormat = CompressionFormat.None;
 791                }
 792            }
 793
 794            public void AddCompressedMessageProperties(Message message, string supportedCompressionTypes)
 795            {
 796                message.Properties.Add(SupportedCompressionTypesMessageProperty, supportedCompressionTypes);
 797            }
 798
 799            private static bool ContentTypeEqualsOrStartsWith(string contentType, string supportedContentType)
 800            {
 801                return contentType == supportedContentType || contentType.StartsWith(supportedContentType, StringCompari
 802            }
 803
 804            private CompressionFormat CheckContentType(string contentType)
 805            {
 806                CompressionFormat compressionFormat = CompressionFormat.None;
 807                if (contentType == null)
 808                {
 809                    compressionFormat = _sessionCompressionFormat;
 810                }
 811                else
 812                {
 813                    if (!CompressionEnabled)
 814                    {
 815                        if (!ContentTypeEqualsOrStartsWith(contentType, ContentType))
 816                        {
 817                            throw Fx.Exception.AsError(new ProtocolException(SR.Format(SR.EncoderUnrecognizedContentType
 818                        }
 819                    }
 820                    else
 821                    {
 822                        if (_factory.CompressionFormat == CompressionFormat.GZip && ContentTypeEqualsOrStartsWith(conten
 823                        {
 824                            compressionFormat = CompressionFormat.GZip;
 825                        }
 826                        else if (_factory.CompressionFormat == CompressionFormat.Deflate && ContentTypeEqualsOrStartsWit
 827                        {
 828                            compressionFormat = CompressionFormat.Deflate;
 829                        }
 830                        else if (ContentTypeEqualsOrStartsWith(contentType, _normalContentType))
 831                        {
 832                            compressionFormat = CompressionFormat.None;
 833                        }
 834                        else
 835                        {
 836                            throw Fx.Exception.AsError(new ProtocolException(SR.Format(SR.EncoderUnrecognizedContentType
 837                        }
 838                    }
 839                }
 840
 841                return compressionFormat;
 842            }
 843
 844            private CompressionFormat CheckCompressedWrite(Message message)
 845            {
 846                CompressionFormat compressionFormat = _sessionCompressionFormat;
 847                if (compressionFormat != CompressionFormat.None && !_isSession)
 848                {
 849                    if (message.Properties.TryGetValue<string>(SupportedCompressionTypesMessageProperty, out string acce
 850                        acceptEncoding != null)
 851                    {
 852                        acceptEncoding = acceptEncoding.ToLowerInvariant();
 853                        if ((compressionFormat == CompressionFormat.GZip &&
 854                            !acceptEncoding.Contains(MessageEncoderCompressionHandler.GZipContentEncoding)) ||
 855                            (compressionFormat == CompressionFormat.Deflate &&
 856                            !acceptEncoding.Contains(MessageEncoderCompressionHandler.DeflateContentEncoding)))
 857                        {
 858                            compressionFormat = CompressionFormat.None;
 859                        }
 860                    }
 861                }
 862                return compressionFormat;
 863            }
 864        }
 865
 866        private class XmlBinaryWriterSessionWithQuota : XmlBinaryWriterSession
 867        {
 868            private int _bytesRemaining;
 869            private List<XmlDictionaryString> _newStrings;
 870
 871            public XmlBinaryWriterSessionWithQuota(int maxSessionSize)
 872            {
 873                _bytesRemaining = maxSessionSize;
 874            }
 875
 876            public bool HasNewStrings
 877            {
 878                get { return _newStrings != null; }
 879            }
 880
 881            public override bool TryAdd(XmlDictionaryString s, out int key)
 882            {
 883                if (_bytesRemaining == 0)
 884                {
 885                    key = -1;
 886                    return false;
 887                }
 888
 889                int bytesRequired = Encoding.UTF8.GetByteCount(s.Value);
 890                bytesRequired += IntEncoder.GetEncodedSize(bytesRequired);
 891
 892                if (bytesRequired > _bytesRemaining)
 893                {
 894                    key = -1;
 895                    _bytesRemaining = 0;
 896                    return false;
 897                }
 898
 899                if (base.TryAdd(s, out key))
 900                {
 901                    if (_newStrings == null)
 902                    {
 903                        _newStrings = new List<XmlDictionaryString>();
 904                    }
 905                    _newStrings.Add(s);
 906                    _bytesRemaining -= bytesRequired;
 907                    return true;
 908                }
 909                else
 910                {
 911                    return false;
 912                }
 913            }
 914
 915            public IList<XmlDictionaryString> GetNewStrings()
 916            {
 917                return _newStrings;
 918            }
 919
 920            public void ClearNewStrings()
 921            {
 922                _newStrings = null;
 923            }
 924        }
 925    }
 926
 927    internal class BinaryFormatBuilder
 928    {
 929        private readonly List<byte> _bytes;
 930
 931        public BinaryFormatBuilder()
 932        {
 933            _bytes = new List<byte>();
 934        }
 935
 936        public int Count
 937        {
 938            get { return _bytes.Count; }
 939        }
 940
 941        public void AppendPrefixDictionaryElement(char prefix, int key)
 942        {
 943            AppendNode(XmlBinaryNodeType.PrefixDictionaryElementA + GetPrefixOffset(prefix));
 944            AppendKey(key);
 945        }
 946
 947        public void AppendDictionaryXmlnsAttribute(char prefix, int key)
 948        {
 949            AppendNode(XmlBinaryNodeType.DictionaryXmlnsAttribute);
 950            AppendUtf8(prefix);
 951            AppendKey(key);
 952        }
 953
 954        public void AppendPrefixDictionaryAttribute(char prefix, int key, char value)
 955        {
 956            AppendNode(XmlBinaryNodeType.PrefixDictionaryAttributeA + GetPrefixOffset(prefix));
 957            AppendKey(key);
 958            if (value == '1')
 959            {
 960                AppendNode(XmlBinaryNodeType.OneText);
 961            }
 962            else
 963            {
 964                AppendNode(XmlBinaryNodeType.Chars8Text);
 965                AppendUtf8(value);
 966            }
 967        }
 968
 969        public void AppendDictionaryAttribute(char prefix, int key, char value)
 970        {
 971            AppendNode(XmlBinaryNodeType.DictionaryAttribute);
 972            AppendUtf8(prefix);
 973            AppendKey(key);
 974            AppendNode(XmlBinaryNodeType.Chars8Text);
 975            AppendUtf8(value);
 976        }
 977
 978        public void AppendDictionaryTextWithEndElement(int key)
 979        {
 980            AppendNode(XmlBinaryNodeType.DictionaryTextWithEndElement);
 981            AppendKey(key);
 982        }
 983
 984        public void AppendDictionaryTextWithEndElement()
 985        {
 986            AppendNode(XmlBinaryNodeType.DictionaryTextWithEndElement);
 987        }
 988
 989        public void AppendUniqueIDWithEndElement()
 990        {
 991            AppendNode(XmlBinaryNodeType.UniqueIdTextWithEndElement);
 992        }
 993
 994        public void AppendEndElement()
 995        {
 996            AppendNode(XmlBinaryNodeType.EndElement);
 997        }
 998
 999        private void AppendKey(int key)
 1000        {
 1001            if (key < 0 || key >= 0x4000)
 1002            {
 1003                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(key), k
 1004                    SR.Format(SR.ValueMustBeInRange, 0, 0x4000)));
 1005            }
 1006            if (key >= 0x80)
 1007            {
 1008                AppendByte((key & 0x7f) | 0x80);
 1009                AppendByte(key >> 7);
 1010            }
 1011            else
 1012            {
 1013                AppendByte(key);
 1014            }
 1015        }
 1016
 1017        private void AppendNode(XmlBinaryNodeType value)
 1018        {
 1019            AppendByte((int)value);
 1020        }
 1021
 1022        private void AppendByte(int value)
 1023        {
 1024            if (value < 0 || value > 0xFF)
 1025            {
 1026                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(value),
 1027                    SR.Format(SR.ValueMustBeInRange, 0, 0xFF)));
 1028            }
 1029            _bytes.Add((byte)value);
 1030        }
 1031
 1032        private void AppendUtf8(char value)
 1033        {
 1034            AppendByte(1);
 1035            AppendByte((int)value);
 1036        }
 1037
 1038        public int GetStaticKey(int value)
 1039        {
 1040            return value * 2;
 1041        }
 1042
 1043        public int GetSessionKey(int value)
 1044        {
 1045            return value * 2 + 1;
 1046        }
 1047
 1048        private int GetPrefixOffset(char prefix)
 1049        {
 1050            if (prefix < 'a' || prefix > 'z')
 1051            {
 1052                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(prefix)
 1053                    SR.Format(SR.ValueMustBeInRange, 'a', 'z')));
 1054            }
 1055            return prefix - 'a';
 1056        }
 1057
 1058        public byte[] ToByteArray()
 1059        {
 1060            byte[] array = _bytes.ToArray();
 1061            _bytes.Clear();
 1062            return array;
 1063        }
 1064    }
 1065
 1066    internal static class BinaryFormatParser
 1067    {
 1068        public static bool IsSessionKey(int value)
 1069        {
 1070            return (value & 1) != 0;
 1071        }
 1072
 1073        public static int GetSessionKey(int value)
 1074        {
 1075            return value / 2;
 1076        }
 1077
 1078        public static int GetStaticKey(int value)
 1079        {
 1080            return value / 2;
 1081        }
 1082
 1083        public static int ParseInt32(byte[] buffer, int offset, int size)
 1084        {
 1085            switch (size)
 1086            {
 1087                case 1:
 1088                    return buffer[offset];
 1089                case 2:
 1090                    return (buffer[offset] & 0x7f) + (buffer[offset + 1] << 7);
 1091                case 3:
 1092                    return (buffer[offset] & 0x7f) + ((buffer[offset + 1] & 0x7f) << 7) + (buffer[offset + 2] << 14);
 1093                case 4:
 1094                    return (buffer[offset] & 0x7f) + ((buffer[offset + 1] & 0x7f) << 7) + ((buffer[offset + 2] & 0x7f) <
 1095                default:
 1096                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(siz
 1097                        SR.Format(SR.ValueMustBeInRange, 1, 4)));
 1098            }
 1099        }
 1100
 1101        public static int ParseKey(byte[] buffer, int offset, int size)
 1102        {
 1103            return ParseInt32(buffer, offset, size);
 1104        }
 1105
 1106        public static unsafe UniqueId ParseUniqueID(byte[] buffer, int offset, int size)
 1107        {
 1108            return new UniqueId(buffer, offset);
 1109        }
 1110
 1111        public static int MatchBytes(byte[] buffer, int offset, int size, byte[] buffer2)
 1112        {
 1113            if (size < buffer2.Length)
 1114            {
 1115                return 0;
 1116            }
 1117            int j = offset;
 1118            for (int i = 0; i < buffer2.Length; i++, j++)
 1119            {
 1120                if (buffer2[i] != buffer[j])
 1121                {
 1122                    return 0;
 1123                }
 1124            }
 1125            return buffer2.Length;
 1126        }
 1127
 1128
 1129        public static bool MatchAttributeNode(byte[] buffer, int offset, int size)
 1130        {
 1131            const XmlBinaryNodeType minAttribute = XmlBinaryNodeType.ShortAttribute;
 1132            const XmlBinaryNodeType maxAttribute = XmlBinaryNodeType.DictionaryAttribute;
 1133            if (size < 1)
 1134            {
 1135                return false;
 1136            }
 1137            XmlBinaryNodeType nodeType = (XmlBinaryNodeType)buffer[offset];
 1138            return nodeType >= minAttribute && nodeType <= maxAttribute;
 1139        }
 1140
 1141        public static int MatchKey(byte[] buffer, int offset, int size)
 1142        {
 1143            return MatchInt32(buffer, offset, size);
 1144        }
 1145
 1146        public static int MatchInt32(byte[] buffer, int offset, int size)
 1147        {
 1148            if (size > 0)
 1149            {
 1150                if ((buffer[offset] & 0x80) == 0)
 1151                {
 1152                    return 1;
 1153                }
 1154            }
 1155            if (size > 1)
 1156            {
 1157                if ((buffer[offset + 1] & 0x80) == 0)
 1158                {
 1159                    return 2;
 1160                }
 1161            }
 1162            if (size > 2)
 1163            {
 1164                if ((buffer[offset + 2] & 0x80) == 0)
 1165                {
 1166                    return 3;
 1167                }
 1168            }
 1169            if (size > 3)
 1170            {
 1171                if ((buffer[offset + 3] & 0x80) == 0)
 1172                {
 1173                    return 4;
 1174                }
 1175            }
 1176
 1177            return 0;
 1178        }
 1179
 1180        public static int MatchUniqueID(byte[] buffer, int offset, int size)
 1181        {
 1182            if (size < 16)
 1183            {
 1184                return 0;
 1185            }
 1186            return 16;
 1187        }
 1188    }
 1189
 1190    internal class MessagePatterns
 1191    {
 1192        private static readonly byte[] s_commonFragment; // <Envelope><Headers><Action>
 1193        private static readonly byte[] s_requestFragment1; // </Action><MessageID>
 1194        private static readonly byte[] s_requestFragment2; // </MessageID><ReplyTo>...</ReplyTo><To>session-to-key</To><
 1195        private static readonly byte[] s_responseFragment1; // </Action><RelatesTo>
 1196        private static readonly byte[] s_responseFragment2; // </RelatesTo><To>static-anonymous-key</To></Headers><Body>
 1197        private static readonly byte[] s_bodyFragment; // <Envelope><Body>
 1198        private const int ToValueSessionKey = 1;
 1199        private readonly IXmlDictionary _dictionary;
 1200        private readonly XmlBinaryReaderSession _readerSession;
 1201        private ToHeader _toHeader;
 1202        private readonly MessageVersion _messageVersion;
 1203
 1204        static MessagePatterns()
 1205        {
 31206            BinaryFormatBuilder builder = new BinaryFormatBuilder();
 1207
 31208            MessageDictionary messageDictionary = XD.MessageDictionary;
 31209            Message12Dictionary message12Dictionary = XD.Message12Dictionary;
 31210            AddressingDictionary addressingDictionary = XD.AddressingDictionary;
 31211            Addressing10Dictionary addressing10Dictionary = XD.Addressing10Dictionary;
 1212
 31213            char messagePrefix = MessageStrings.Prefix[0];
 31214            char addressingPrefix = AddressingStrings.Prefix[0];
 1215
 1216            // <s:Envelope xmlns:s="soap-ns" xmlns="addressing-ns">
 31217            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Envelope.Key));
 31218            builder.AppendDictionaryXmlnsAttribute(messagePrefix, builder.GetStaticKey(message12Dictionary.Namespace.Key
 31219            builder.AppendDictionaryXmlnsAttribute(addressingPrefix, builder.GetStaticKey(addressing10Dictionary.Namespa
 1220
 1221            // <s:Header>
 31222            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Header.Key));
 1223
 1224            // <a:Action>...
 31225            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.Action.Key
 31226            builder.AppendPrefixDictionaryAttribute(messagePrefix, builder.GetStaticKey(messageDictionary.MustUnderstand
 31227            builder.AppendDictionaryTextWithEndElement();
 31228            s_commonFragment = builder.ToByteArray();
 1229
 1230            // <a:MessageID>...
 31231            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.MessageId.
 31232            builder.AppendUniqueIDWithEndElement();
 31233            s_requestFragment1 = builder.ToByteArray();
 1234
 1235            // <a:ReplyTo><a:Address>static-anonymous-key</a:Address></a:ReplyTo>
 31236            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.ReplyTo.Ke
 31237            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.Address.Ke
 31238            builder.AppendDictionaryTextWithEndElement(builder.GetStaticKey(addressing10Dictionary.Anonymous.Key));
 31239            builder.AppendEndElement();
 1240
 1241            // <a:To>session-to-key</a:To>
 31242            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.To.Key));
 31243            builder.AppendPrefixDictionaryAttribute(messagePrefix, builder.GetStaticKey(messageDictionary.MustUnderstand
 31244            builder.AppendDictionaryTextWithEndElement(builder.GetSessionKey(ToValueSessionKey));
 1245
 1246            // </s:Header>
 31247            builder.AppendEndElement();
 1248
 1249            // <s:Body>
 31250            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Body.Key));
 31251            s_requestFragment2 = builder.ToByteArray();
 1252
 1253            // <a:RelatesTo>...
 31254            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.RelatesTo.
 31255            builder.AppendUniqueIDWithEndElement();
 31256            s_responseFragment1 = builder.ToByteArray();
 1257
 1258            // <a:To>static-anonymous-key</a:To>
 31259            builder.AppendPrefixDictionaryElement(addressingPrefix, builder.GetStaticKey(addressingDictionary.To.Key));
 31260            builder.AppendPrefixDictionaryAttribute(messagePrefix, builder.GetStaticKey(messageDictionary.MustUnderstand
 31261            builder.AppendDictionaryTextWithEndElement(builder.GetStaticKey(addressing10Dictionary.Anonymous.Key));
 1262
 1263            // </s:Header>
 31264            builder.AppendEndElement();
 1265
 1266            // <s:Body>
 31267            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Body.Key));
 31268            s_responseFragment2 = builder.ToByteArray();
 1269
 1270            // <s:Envelope xmlns:s="soap-ns" xmlns="addressing-ns">
 31271            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Envelope.Key));
 31272            builder.AppendDictionaryXmlnsAttribute(messagePrefix, builder.GetStaticKey(message12Dictionary.Namespace.Key
 31273            builder.AppendDictionaryXmlnsAttribute(addressingPrefix, builder.GetStaticKey(addressing10Dictionary.Namespa
 1274
 1275            // <s:Body>
 31276            builder.AppendPrefixDictionaryElement(messagePrefix, builder.GetStaticKey(messageDictionary.Body.Key));
 31277            s_bodyFragment = builder.ToByteArray();
 31278        }
 1279
 681280        public MessagePatterns(IXmlDictionary dictionary, XmlBinaryReaderSession readerSession, MessageVersion messageVe
 1281        {
 681282            _dictionary = dictionary;
 681283            _readerSession = readerSession;
 681284            _messageVersion = messageVersion;
 681285        }
 1286
 1287        public Message TryCreateMessage(byte[] buffer, int offset, int size, BufferManager bufferManager, BufferedMessag
 1288        {
 1289            RelatesToHeader relatesToHeader;
 1290            MessageIDHeader messageIDHeader;
 1291            XmlDictionaryString toString;
 1292
 811293            int currentOffset = offset;
 811294            int remainingSize = size;
 1295
 811296            int bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, s_commonFragment);
 811297            if (bytesMatched == 0)
 1298            {
 111299                return null;
 1300            }
 701301            currentOffset += bytesMatched;
 701302            remainingSize -= bytesMatched;
 1303
 701304            bytesMatched = BinaryFormatParser.MatchKey(buffer, currentOffset, remainingSize);
 701305            if (bytesMatched == 0)
 1306            {
 01307                return null;
 1308            }
 701309            int actionOffset = currentOffset;
 701310            int actionSize = bytesMatched;
 701311            currentOffset += bytesMatched;
 701312            remainingSize -= bytesMatched;
 1313
 1314            int totalBytesMatched;
 1315
 701316            bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, s_requestFragment1);
 701317            if (bytesMatched != 0)
 1318            {
 681319                currentOffset += bytesMatched;
 681320                remainingSize -= bytesMatched;
 1321
 681322                bytesMatched = BinaryFormatParser.MatchUniqueID(buffer, currentOffset, remainingSize);
 681323                if (bytesMatched == 0)
 1324                {
 01325                    return null;
 1326                }
 681327                int messageIDOffset = currentOffset;
 681328                int messageIDSize = bytesMatched;
 681329                currentOffset += bytesMatched;
 681330                remainingSize -= bytesMatched;
 1331
 681332                bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, s_requestFragment2);
 681333                if (bytesMatched == 0)
 1334                {
 01335                    return null;
 1336                }
 681337                currentOffset += bytesMatched;
 681338                remainingSize -= bytesMatched;
 1339
 681340                if (BinaryFormatParser.MatchAttributeNode(buffer, currentOffset, remainingSize))
 1341                {
 01342                    return null;
 1343                }
 1344
 681345                UniqueId messageId = BinaryFormatParser.ParseUniqueID(buffer, messageIDOffset, messageIDSize);
 681346                messageIDHeader = MessageIDHeader.Create(messageId, _messageVersion.Addressing);
 681347                relatesToHeader = null;
 1348
 681349                if (!_readerSession.TryLookup(ToValueSessionKey, out toString))
 1350                {
 01351                    return null;
 1352                }
 1353
 681354                totalBytesMatched = s_requestFragment1.Length + messageIDSize + s_requestFragment2.Length;
 1355            }
 1356            else
 1357            {
 21358                bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, s_responseFragment1);
 1359
 21360                if (bytesMatched == 0)
 1361                {
 11362                    return null;
 1363                }
 1364
 11365                currentOffset += bytesMatched;
 11366                remainingSize -= bytesMatched;
 1367
 11368                bytesMatched = BinaryFormatParser.MatchUniqueID(buffer, currentOffset, remainingSize);
 11369                if (bytesMatched == 0)
 1370                {
 01371                    return null;
 1372                }
 11373                int messageIDOffset = currentOffset;
 11374                int messageIDSize = bytesMatched;
 11375                currentOffset += bytesMatched;
 11376                remainingSize -= bytesMatched;
 1377
 11378                bytesMatched = BinaryFormatParser.MatchBytes(buffer, currentOffset, remainingSize, s_responseFragment2);
 11379                if (bytesMatched == 0)
 1380                {
 11381                    return null;
 1382                }
 01383                currentOffset += bytesMatched;
 01384                remainingSize -= bytesMatched;
 1385
 01386                if (BinaryFormatParser.MatchAttributeNode(buffer, currentOffset, remainingSize))
 1387                {
 01388                    return null;
 1389                }
 1390
 01391                UniqueId messageId = BinaryFormatParser.ParseUniqueID(buffer, messageIDOffset, messageIDSize);
 01392                relatesToHeader = RelatesToHeader.Create(messageId, _messageVersion.Addressing);
 01393                messageIDHeader = null;
 01394                toString = XD.Addressing10Dictionary.Anonymous;
 1395
 01396                totalBytesMatched = s_responseFragment1.Length + messageIDSize + s_responseFragment2.Length;
 1397            }
 1398
 681399            totalBytesMatched += s_commonFragment.Length + actionSize;
 1400
 681401            int actionKey = BinaryFormatParser.ParseKey(buffer, actionOffset, actionSize);
 1402
 681403            if (!TryLookupKey(actionKey, out XmlDictionaryString actionString))
 1404            {
 01405                return null;
 1406            }
 1407
 681408            ActionHeader actionHeader = ActionHeader.Create(actionString, _messageVersion.Addressing);
 1409
 681410            if (_toHeader == null)
 1411            {
 581412                _toHeader = ToHeader.Create(new Uri(toString.Value), _messageVersion.Addressing);
 1413            }
 1414
 681415            int abandonedSize = totalBytesMatched - s_bodyFragment.Length;
 1416
 681417            offset += abandonedSize;
 681418            size -= abandonedSize;
 1419
 681420            Buffer.BlockCopy(s_bodyFragment, 0, buffer, offset, s_bodyFragment.Length);
 1421
 681422            messageData.Open(new ArraySegment<byte>(buffer, offset, size), bufferManager);
 1423
 681424            PatternMessage patternMessage = new PatternMessage(messageData, _messageVersion);
 1425
 681426            MessageHeaders headers = patternMessage.Headers;
 681427            headers.AddActionHeader(actionHeader);
 681428            if (messageIDHeader != null)
 1429            {
 681430                headers.AddMessageIDHeader(messageIDHeader);
 681431                headers.AddReplyToHeader(ReplyToHeader.AnonymousReplyTo10);
 1432            }
 1433            else
 1434            {
 01435                headers.AddRelatesToHeader(relatesToHeader);
 1436            }
 681437            headers.AddToHeader(_toHeader);
 1438
 681439            return patternMessage;
 1440        }
 1441
 1442        private bool TryLookupKey(int key, out XmlDictionaryString result)
 1443        {
 681444            if (BinaryFormatParser.IsSessionKey(key))
 1445            {
 681446                return _readerSession.TryLookup(BinaryFormatParser.GetSessionKey(key), out result);
 1447            }
 1448            else
 1449            {
 01450                return _dictionary.TryLookup(BinaryFormatParser.GetStaticKey(key), out result);
 1451            }
 1452        }
 1453
 1454        private sealed class PatternMessage : ReceivedMessage
 1455        {
 1456            private IBufferedMessageData _messageData;
 1457            private readonly MessageHeaders _headers;
 1458            private RecycledMessageState _recycledMessageState;
 1459            private readonly MessageProperties _properties;
 1460            private XmlDictionaryReader _reader;
 1461
 681462            public PatternMessage(IBufferedMessageData messageData, MessageVersion messageVersion)
 1463            {
 681464                _messageData = messageData;
 681465                _recycledMessageState = messageData.TakeMessageState();
 681466                if (_recycledMessageState == null)
 1467                {
 681468                    _recycledMessageState = new RecycledMessageState();
 1469                }
 681470                _properties = _recycledMessageState.TakeProperties();
 681471                if (_properties == null)
 1472                {
 681473                    _properties = new MessageProperties();
 1474                }
 681475                _headers = _recycledMessageState.TakeHeaders();
 681476                if (_headers == null)
 1477                {
 681478                    _headers = new MessageHeaders(messageVersion);
 1479                }
 1480                else
 1481                {
 01482                    _headers.Init(messageVersion);
 1483                }
 681484                XmlDictionaryReader reader = messageData.GetMessageReader();
 681485                reader.ReadStartElement();
 681486                VerifyStartBody(reader, messageVersion.Envelope);
 681487                ReadStartBody(reader);
 681488                _reader = reader;
 681489            }
 1490
 01491            public PatternMessage(IBufferedMessageData messageData, MessageVersion messageVersion,
 01492                KeyValuePair<string, object>[] properties, MessageHeaders headers)
 1493            {
 01494                _messageData = messageData;
 01495                _messageData.Open();
 01496                _recycledMessageState = _messageData.TakeMessageState();
 01497                if (_recycledMessageState == null)
 1498                {
 01499                    _recycledMessageState = new RecycledMessageState();
 1500                }
 1501
 01502                _properties = _recycledMessageState.TakeProperties();
 01503                if (_properties == null)
 1504                {
 01505                    _properties = new MessageProperties();
 1506                }
 01507                if (properties != null)
 1508                {
 01509                    _properties.CopyProperties(properties);
 1510                }
 1511
 01512                _headers = _recycledMessageState.TakeHeaders();
 01513                if (_headers == null)
 1514                {
 01515                    _headers = new MessageHeaders(messageVersion);
 1516                }
 01517                if (headers != null)
 1518                {
 01519                    _headers.CopyHeadersFrom(headers);
 1520                }
 1521
 01522                XmlDictionaryReader reader = messageData.GetMessageReader();
 01523                reader.ReadStartElement();
 01524                VerifyStartBody(reader, messageVersion.Envelope);
 01525                ReadStartBody(reader);
 01526                _reader = reader;
 01527            }
 1528
 1529
 1530            public override MessageHeaders Headers
 1531            {
 1532                get
 1533                {
 8541534                    if (IsDisposed)
 1535                    {
 01536                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateMessageDisposedException());
 1537                    }
 8541538                    return _headers;
 1539                }
 1540            }
 1541
 1542            public override MessageProperties Properties
 1543            {
 1544                get
 1545                {
 4171546                    if (IsDisposed)
 1547                    {
 01548                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateMessageDisposedException());
 1549                    }
 4171550                    return _properties;
 1551                }
 1552            }
 1553
 1554            public override MessageVersion Version
 1555            {
 1556                get
 1557                {
 3461558                    if (IsDisposed)
 1559                    {
 01560                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateMessageDisposedException());
 1561                    }
 3461562                    return _headers.MessageVersion;
 1563                }
 1564            }
 1565
 1566            public override RecycledMessageState RecycledMessageState
 1567            {
 01568                get { return _recycledMessageState; }
 1569            }
 1570
 1571            private XmlDictionaryReader GetBufferedReaderAtBody()
 1572            {
 01573                XmlDictionaryReader reader = _messageData.GetMessageReader();
 01574                reader.ReadStartElement();
 01575                reader.ReadStartElement();
 01576                return reader;
 1577            }
 1578
 1579            protected override void OnBodyToString(XmlDictionaryWriter writer)
 1580            {
 01581                using (XmlDictionaryReader reader = GetBufferedReaderAtBody())
 1582                {
 01583                    while (reader.NodeType != XmlNodeType.EndElement)
 1584                    {
 01585                        writer.WriteNode(reader, false);
 1586                    }
 01587                }
 01588            }
 1589
 1590            protected override void OnClose()
 1591            {
 661592                Exception ex = null;
 1593                try
 1594                {
 661595                    base.OnClose();
 661596                }
 1597                catch (Exception e)
 1598                {
 01599                    if (Fx.IsFatal(e))
 1600                    {
 01601                        throw;
 1602                    }
 01603                    ex = e;
 01604                }
 1605
 1606                try
 1607                {
 661608                    _properties.Dispose();
 661609                }
 01610                catch (Exception e)
 1611                {
 01612                    if (Fx.IsFatal(e))
 1613                    {
 01614                        throw;
 1615                    }
 01616                    if (ex == null)
 1617                    {
 01618                        ex = e;
 1619                    }
 01620                }
 1621
 1622                try
 1623                {
 661624                    if (_reader != null)
 1625                    {
 01626                        _reader.Dispose();
 1627                    }
 661628                }
 01629                catch (Exception e)
 1630                {
 01631                    if (Fx.IsFatal(e))
 1632                    {
 01633                        throw;
 1634                    }
 01635                    if (ex == null)
 1636                    {
 01637                        ex = e;
 1638                    }
 01639                }
 1640
 1641                try
 1642                {
 661643                    _recycledMessageState.ReturnHeaders(_headers);
 661644                    _recycledMessageState.ReturnProperties(_properties);
 661645                    _messageData.ReturnMessageState(_recycledMessageState);
 661646                    _recycledMessageState = null;
 661647                    _messageData.Close();
 661648                    _messageData = null;
 661649                }
 01650                catch (Exception e)
 1651                {
 01652                    if (Fx.IsFatal(e))
 1653                    {
 01654                        throw;
 1655                    }
 01656                    if (ex == null)
 1657                    {
 01658                        ex = e;
 1659                    }
 01660                }
 1661
 661662                if (ex != null)
 1663                {
 01664                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex);
 1665                }
 661666            }
 1667
 1668            protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
 1669            {
 01670                KeyValuePair<string, object>[] properties = new KeyValuePair<string, object>[Properties.Count];
 01671                ((ICollection<KeyValuePair<string, object>>)Properties).CopyTo(properties, 0);
 01672                _messageData.EnableMultipleUsers();
 01673                return new PatternMessageBuffer(_messageData, Version, properties, _headers);
 1674            }
 1675
 1676            protected override XmlDictionaryReader OnGetReaderAtBodyContents()
 1677            {
 661678                XmlDictionaryReader reader = _reader;
 661679                _reader = null;
 661680                return reader;
 1681            }
 1682
 1683            protected override string OnGetBodyAttribute(string localName, string ns)
 1684            {
 01685                return null;
 1686            }
 1687        }
 1688
 1689        private class PatternMessageBuffer : MessageBuffer
 1690        {
 1691            private bool _closed;
 1692            private MessageHeaders _headers;
 1693            private IBufferedMessageData _messageDataAtBody;
 1694            private MessageVersion _messageVersion;
 1695            private KeyValuePair<string, object>[] _properties;
 1696            private RecycledMessageState _recycledMessageState;
 1697
 01698            public PatternMessageBuffer(IBufferedMessageData messageDataAtBody, MessageVersion messageVersion,
 01699                KeyValuePair<string, object>[] properties, MessageHeaders headers)
 1700            {
 01701                _messageDataAtBody = messageDataAtBody;
 01702                _messageDataAtBody.Open();
 1703
 01704                _recycledMessageState = _messageDataAtBody.TakeMessageState();
 01705                if (_recycledMessageState == null)
 1706                {
 01707                    _recycledMessageState = new RecycledMessageState();
 1708                }
 1709
 01710                _headers = _recycledMessageState.TakeHeaders();
 01711                if (_headers == null)
 1712                {
 01713                    _headers = new MessageHeaders(messageVersion);
 1714                }
 01715                _headers.CopyHeadersFrom(headers);
 01716                _properties = properties;
 01717                _messageVersion = messageVersion;
 01718            }
 1719
 1720            public override int BufferSize
 1721            {
 1722                get
 1723                {
 01724                    lock (ThisLock)
 1725                    {
 01726                        if (_closed)
 1727                        {
 01728                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
 1729                        }
 1730
 01731                        return _messageDataAtBody.Buffer.Count;
 1732                    }
 01733                }
 1734            }
 1735
 01736            private object ThisLock { get; } = new object();
 1737
 1738            public override void Close()
 1739            {
 01740                lock (ThisLock)
 1741                {
 01742                    if (!_closed)
 1743                    {
 01744                        _closed = true;
 01745                        _recycledMessageState.ReturnHeaders(_headers);
 01746                        _messageDataAtBody.ReturnMessageState(_recycledMessageState);
 01747                        _messageDataAtBody.Close();
 01748                        _recycledMessageState = null;
 01749                        _messageDataAtBody = null;
 01750                        _properties = null;
 01751                        _messageVersion = null;
 01752                        _headers = null;
 1753                    }
 01754                }
 01755            }
 1756
 1757            public override Message CreateMessage()
 1758            {
 01759                lock (ThisLock)
 1760                {
 01761                    if (_closed)
 1762                    {
 01763                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
 1764                    }
 1765
 01766                    return new PatternMessage(_messageDataAtBody, _messageVersion, _properties,
 01767                        _headers);
 1768                }
 01769            }
 1770        }
 1771    }
 1772}