5accd13b6acf9d31576371d48a0a7e9e9bd062e3
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / MessageHeaders.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Collections;
7     using System.Collections.Generic;
8     using System.Collections.ObjectModel;
9     using System.Diagnostics;
10     using System.Runtime;
11     using System.Runtime.Serialization;
12     using System.ServiceModel;
13     using System.ServiceModel.Diagnostics;
14     using System.ServiceModel.Dispatcher;
15     using System.Xml;
16
17     public sealed class MessageHeaders : IEnumerable<MessageHeaderInfo>
18     {
19         int collectionVersion;
20         int headerCount;
21         Header[] headers;
22         MessageVersion version;
23         IBufferedMessageData bufferedMessageData;
24         UnderstoodHeaders understoodHeaders;
25         const int InitialHeaderCount = 4;
26         const int MaxRecycledArrayLength = 8;
27         static XmlDictionaryString[] localNames;
28
29         internal const string WildcardAction = "*";
30
31         // The highest node and attribute counts reached by the BVTs were 1829 and 667 respectively.
32         const int MaxBufferedHeaderNodes = 4096;
33         const int MaxBufferedHeaderAttributes = 2048;
34         int nodeCount = 0;
35         int attrCount = 0;
36         bool understoodHeadersModified;
37
38         public MessageHeaders(MessageVersion version, int initialSize)
39         {
40             Init(version, initialSize);
41         }
42
43         public MessageHeaders(MessageVersion version)
44             : this(version, InitialHeaderCount)
45         {
46         }
47
48         internal MessageHeaders(MessageVersion version, XmlDictionaryReader reader, XmlAttributeHolder[] envelopeAttributes, XmlAttributeHolder[] headerAttributes, ref int maxSizeOfHeaders)
49             : this(version)
50         {
51             if (maxSizeOfHeaders < 0)
52             {
53                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
54                     new ArgumentOutOfRangeException("maxSizeOfHeaders", maxSizeOfHeaders,
55                     SR.GetString(SR.ValueMustBeNonNegative)));
56             }
57
58             if (version == null)
59                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
60             if (reader == null)
61                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reader"));
62             if (reader.IsEmptyElement)
63             {
64                 reader.Read();
65                 return;
66             }
67             XmlBuffer xmlBuffer = null;
68             EnvelopeVersion envelopeVersion = version.Envelope;
69             reader.ReadStartElement(XD.MessageDictionary.Header, envelopeVersion.DictionaryNamespace);
70             while (reader.IsStartElement())
71             {
72                 if (xmlBuffer == null)
73                     xmlBuffer = new XmlBuffer(maxSizeOfHeaders);
74                 BufferedHeader bufferedHeader = new BufferedHeader(version, xmlBuffer, reader, envelopeAttributes, headerAttributes);
75                 HeaderProcessing processing = bufferedHeader.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
76                 HeaderKind kind = GetHeaderKind(bufferedHeader);
77                 if (kind != HeaderKind.Unknown)
78                 {
79                     processing |= HeaderProcessing.Understood;
80                     MessageHeaders.TraceUnderstood(bufferedHeader);
81                 }
82                 Header newHeader = new Header(kind, bufferedHeader, processing);
83                 AddHeader(newHeader);
84             }
85             if (xmlBuffer != null)
86             {
87                 xmlBuffer.Close();
88                 maxSizeOfHeaders -= xmlBuffer.BufferSize;
89             }
90             reader.ReadEndElement();
91             this.collectionVersion = 0;
92         }
93
94         internal MessageHeaders(MessageVersion version, XmlDictionaryReader reader, IBufferedMessageData bufferedMessageData, RecycledMessageState recycledMessageState, bool[] understoodHeaders, bool understoodHeadersModified)
95         {
96             this.headers = new Header[InitialHeaderCount];
97             Init(version, reader, bufferedMessageData, recycledMessageState, understoodHeaders, understoodHeadersModified);
98         }
99
100         internal MessageHeaders(MessageVersion version, MessageHeaders headers, IBufferedMessageData bufferedMessageData)
101         {
102             this.version = version;
103             this.bufferedMessageData = bufferedMessageData;
104             this.headerCount = headers.headerCount;
105             this.headers = new Header[headerCount];
106             Array.Copy(headers.headers, this.headers, headerCount);
107             this.collectionVersion = 0;
108         }
109
110         public MessageHeaders(MessageHeaders collection)
111         {
112             if (collection == null)
113                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("collection");
114
115             Init(collection.version, collection.headers.Length);
116             CopyHeadersFrom(collection);
117             this.collectionVersion = 0;
118         }
119
120         public string Action
121         {
122             get
123             {
124                 int index = FindHeaderProperty(HeaderKind.Action);
125                 if (index < 0)
126                     return null;
127                 ActionHeader actionHeader = headers[index].HeaderInfo as ActionHeader;
128                 if (actionHeader != null)
129                     return actionHeader.Action;
130                 using (XmlDictionaryReader reader = GetReaderAtHeader(index))
131                 {
132                     return ActionHeader.ReadHeaderValue(reader, version.Addressing);
133                 }
134             }
135             set
136             {
137                 if (value != null)
138                     SetActionHeader(ActionHeader.Create(value, version.Addressing));
139                 else
140                     SetHeaderProperty(HeaderKind.Action, null);
141             }
142         }
143
144         internal bool CanRecycle
145         {
146             get { return headers.Length <= MaxRecycledArrayLength; }
147         }
148
149         internal bool ContainsOnlyBufferedMessageHeaders
150         {
151             get { return (bufferedMessageData != null && collectionVersion == 0); }
152         }
153
154         internal int CollectionVersion
155         {
156             get { return collectionVersion; }
157         }
158
159         public int Count
160         {
161             get { return headerCount; }
162         }
163
164         public EndpointAddress FaultTo
165         {
166             get
167             {
168                 int index = FindHeaderProperty(HeaderKind.FaultTo);
169                 if (index < 0)
170                     return null;
171                 FaultToHeader faultToHeader = headers[index].HeaderInfo as FaultToHeader;
172                 if (faultToHeader != null)
173                     return faultToHeader.FaultTo;
174                 using (XmlDictionaryReader reader = GetReaderAtHeader(index))
175                 {
176                     return FaultToHeader.ReadHeaderValue(reader, version.Addressing);
177                 }
178             }
179             set
180             {
181                 if (value != null)
182                     SetFaultToHeader(FaultToHeader.Create(value, version.Addressing));
183                 else
184                     SetHeaderProperty(HeaderKind.FaultTo, null);
185             }
186         }
187
188         public EndpointAddress From
189         {
190             get
191             {
192                 int index = FindHeaderProperty(HeaderKind.From);
193                 if (index < 0)
194                     return null;
195                 FromHeader fromHeader = headers[index].HeaderInfo as FromHeader;
196                 if (fromHeader != null)
197                     return fromHeader.From;
198                 using (XmlDictionaryReader reader = GetReaderAtHeader(index))
199                 {
200                     return FromHeader.ReadHeaderValue(reader, version.Addressing);
201                 }
202             }
203             set
204             {
205                 if (value != null)
206                     SetFromHeader(FromHeader.Create(value, version.Addressing));
207                 else
208                     SetHeaderProperty(HeaderKind.From, null);
209             }
210         }
211
212         internal bool HasMustUnderstandBeenModified
213         {
214             get
215             {
216                 if (understoodHeaders != null)
217                 {
218                     return understoodHeaders.Modified;
219                 }
220                 else
221                 {
222                     return this.understoodHeadersModified;
223                 }
224             }
225         }
226
227         public UniqueId MessageId
228         {
229             get
230             {
231                 int index = FindHeaderProperty(HeaderKind.MessageId);
232                 if (index < 0)
233                     return null;
234                 MessageIDHeader messageIDHeader = headers[index].HeaderInfo as MessageIDHeader;
235                 if (messageIDHeader != null)
236                     return messageIDHeader.MessageId;
237                 using (XmlDictionaryReader reader = GetReaderAtHeader(index))
238                 {
239                     return MessageIDHeader.ReadHeaderValue(reader, version.Addressing);
240                 }
241             }
242             set
243             {
244                 if (value != null)
245                     SetMessageIDHeader(MessageIDHeader.Create(value, version.Addressing));
246                 else
247                     SetHeaderProperty(HeaderKind.MessageId, null);
248             }
249         }
250
251         public MessageVersion MessageVersion
252         {
253             get { return version; }
254         }
255
256         public UniqueId RelatesTo
257         {
258             get
259             {
260                 return GetRelatesTo(RelatesToHeader.ReplyRelationshipType);
261             }
262             set
263             {
264                 SetRelatesTo(RelatesToHeader.ReplyRelationshipType, value);
265             }
266         }
267
268         public EndpointAddress ReplyTo
269         {
270             get
271             {
272                 int index = FindHeaderProperty(HeaderKind.ReplyTo);
273                 if (index < 0)
274                     return null;
275                 ReplyToHeader replyToHeader = headers[index].HeaderInfo as ReplyToHeader;
276                 if (replyToHeader != null)
277                     return replyToHeader.ReplyTo;
278                 using (XmlDictionaryReader reader = GetReaderAtHeader(index))
279                 {
280                     return ReplyToHeader.ReadHeaderValue(reader, version.Addressing);
281                 }
282             }
283             set
284             {
285                 if (value != null)
286                     SetReplyToHeader(ReplyToHeader.Create(value, version.Addressing));
287                 else
288                     SetHeaderProperty(HeaderKind.ReplyTo, null);
289             }
290         }
291
292         public Uri To
293         {
294             get
295             {
296                 int index = FindHeaderProperty(HeaderKind.To);
297                 if (index < 0)
298                     return null;
299                 ToHeader toHeader = headers[index].HeaderInfo as ToHeader;
300                 if (toHeader != null)
301                     return toHeader.To;
302                 using (XmlDictionaryReader reader = GetReaderAtHeader(index))
303                 {
304                     return ToHeader.ReadHeaderValue(reader, version.Addressing);
305                 }
306             }
307             set
308             {
309                 if (value != null)
310                     SetToHeader(ToHeader.Create(value, version.Addressing));
311                 else
312                     SetHeaderProperty(HeaderKind.To, null);
313             }
314         }
315
316         public UnderstoodHeaders UnderstoodHeaders
317         {
318             get
319             {
320                 if (understoodHeaders == null)
321                     understoodHeaders = new UnderstoodHeaders(this, understoodHeadersModified);
322                 return understoodHeaders;
323             }
324         }
325
326         public MessageHeaderInfo this[int index]
327         {
328             get
329             {
330                 if (index < 0 || index >= headerCount)
331                 {
332                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
333                         new ArgumentOutOfRangeException("index", index,
334                         SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
335                 }
336
337                 return headers[index].HeaderInfo;
338             }
339         }
340
341         public void Add(MessageHeader header)
342         {
343             Insert(headerCount, header);
344         }
345
346         internal void AddActionHeader(ActionHeader actionHeader)
347         {
348             Insert(headerCount, actionHeader, HeaderKind.Action);
349         }
350
351         internal void AddMessageIDHeader(MessageIDHeader messageIDHeader)
352         {
353             Insert(headerCount, messageIDHeader, HeaderKind.MessageId);
354         }
355
356         internal void AddRelatesToHeader(RelatesToHeader relatesToHeader)
357         {
358             Insert(headerCount, relatesToHeader, HeaderKind.RelatesTo);
359         }
360
361         internal void AddReplyToHeader(ReplyToHeader replyToHeader)
362         {
363             Insert(headerCount, replyToHeader, HeaderKind.ReplyTo);
364         }
365
366         internal void AddToHeader(ToHeader toHeader)
367         {
368             Insert(headerCount, toHeader, HeaderKind.To);
369         }
370
371         void Add(MessageHeader header, HeaderKind kind)
372         {
373             Insert(headerCount, header, kind);
374         }
375
376         void AddHeader(Header header)
377         {
378             InsertHeader(headerCount, header);
379         }
380
381         internal void AddUnderstood(int i)
382         {
383             headers[i].HeaderProcessing |= HeaderProcessing.Understood;
384             MessageHeaders.TraceUnderstood(headers[i].HeaderInfo);
385         }
386
387         internal void AddUnderstood(MessageHeaderInfo headerInfo)
388         {
389             if (headerInfo == null)
390                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("headerInfo"));
391             for (int i = 0; i < headerCount; i++)
392             {
393                 if ((object)headers[i].HeaderInfo == (object)headerInfo)
394                 {
395                     if ((headers[i].HeaderProcessing & HeaderProcessing.Understood) != 0)
396                     {
397                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(
398                             SR.GetString(SR.HeaderAlreadyUnderstood, headerInfo.Name, headerInfo.Namespace), "headerInfo"));
399                     }
400
401                     AddUnderstood(i);
402                 }
403             }
404         }
405
406         void CaptureBufferedHeaders()
407         {
408             CaptureBufferedHeaders(-1);
409         }
410
411         void CaptureBufferedHeaders(int exceptIndex)
412         {
413             using (XmlDictionaryReader reader = GetBufferedMessageHeaderReaderAtHeaderContents(bufferedMessageData))
414             {
415                 for (int i = 0; i < headerCount; i++)
416                 {
417                     if (reader.NodeType != XmlNodeType.Element)
418                     {
419                         if (reader.MoveToContent() != XmlNodeType.Element)
420                             break;
421                     }
422
423                     Header header = headers[i];
424                     if (i == exceptIndex || header.HeaderType != HeaderType.BufferedMessageHeader)
425                     {
426                         reader.Skip();
427                     }
428                     else
429                     {
430                         headers[i] = new Header(header.HeaderKind, CaptureBufferedHeader(reader,
431                             header.HeaderInfo), header.HeaderProcessing);
432                     }
433                 }
434             }
435             bufferedMessageData = null;
436         }
437
438         BufferedHeader CaptureBufferedHeader(XmlDictionaryReader reader, MessageHeaderInfo headerInfo)
439         {
440             XmlBuffer buffer = new XmlBuffer(int.MaxValue);
441             XmlDictionaryWriter writer = buffer.OpenSection(bufferedMessageData.Quotas);
442             writer.WriteNode(reader, false);
443             buffer.CloseSection();
444             buffer.Close();
445             return new BufferedHeader(version, buffer, 0, headerInfo);
446         }
447
448         BufferedHeader CaptureBufferedHeader(IBufferedMessageData bufferedMessageData, MessageHeaderInfo headerInfo, int bufferedMessageHeaderIndex)
449         {
450             XmlBuffer buffer = new XmlBuffer(int.MaxValue);
451             XmlDictionaryWriter writer = buffer.OpenSection(bufferedMessageData.Quotas);
452             WriteBufferedMessageHeader(bufferedMessageData, bufferedMessageHeaderIndex, writer);
453             buffer.CloseSection();
454             buffer.Close();
455             return new BufferedHeader(version, buffer, 0, headerInfo);
456         }
457
458         BufferedHeader CaptureWriteableHeader(MessageHeader writeableHeader)
459         {
460             XmlBuffer buffer = new XmlBuffer(int.MaxValue);
461             XmlDictionaryWriter writer = buffer.OpenSection(XmlDictionaryReaderQuotas.Max);
462             writeableHeader.WriteHeader(writer, this.version);
463             buffer.CloseSection();
464             buffer.Close();
465             return new BufferedHeader(version, buffer, 0, writeableHeader);
466         }
467
468         public void Clear()
469         {
470             for (int i = 0; i < headerCount; i++)
471                 headers[i] = new Header();
472             headerCount = 0;
473             collectionVersion++;
474             bufferedMessageData = null;
475         }
476
477         public void CopyHeaderFrom(Message message, int headerIndex)
478         {
479             if (message == null)
480                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
481             CopyHeaderFrom(message.Headers, headerIndex);
482         }
483
484         public void CopyHeaderFrom(MessageHeaders collection, int headerIndex)
485         {
486             if (collection == null)
487             {
488                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("collection");
489             }
490
491             if (collection.version != version)
492             {
493 #pragma warning suppress 56506 // Microsoft, collection.version is never null
494                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessageHeaderVersionMismatch, collection.version.ToString(), version.ToString()), "collection"));
495             }
496
497             if (headerIndex < 0 || headerIndex >= collection.headerCount)
498             {
499                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
500                     new ArgumentOutOfRangeException("headerIndex", headerIndex,
501                     SR.GetString(SR.ValueMustBeInRange, 0, collection.headerCount)));
502             }
503             Header header = collection.headers[headerIndex];
504             HeaderProcessing processing = header.HeaderInfo.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
505             if ((header.HeaderProcessing & HeaderProcessing.Understood) != 0 || header.HeaderKind != HeaderKind.Unknown)
506                 processing |= HeaderProcessing.Understood;
507             switch (header.HeaderType)
508             {
509                 case HeaderType.BufferedMessageHeader:
510                     AddHeader(new Header(header.HeaderKind, collection.CaptureBufferedHeader(collection.bufferedMessageData,
511                         header.HeaderInfo, headerIndex), processing));
512                     break;
513                 case HeaderType.ReadableHeader:
514                     AddHeader(new Header(header.HeaderKind, header.ReadableHeader, processing));
515                     break;
516                 case HeaderType.WriteableHeader:
517                     AddHeader(new Header(header.HeaderKind, header.MessageHeader, processing));
518                     break;
519                 default:
520                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, header.HeaderType)));
521             }
522         }
523
524         public void CopyHeadersFrom(Message message)
525         {
526             if (message == null)
527                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
528             CopyHeadersFrom(message.Headers);
529         }
530
531         public void CopyHeadersFrom(MessageHeaders collection)
532         {
533             if (collection == null)
534                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("collection"));
535             for (int i = 0; i < collection.headerCount; i++)
536                 CopyHeaderFrom(collection, i);
537         }
538
539         public void CopyTo(MessageHeaderInfo[] array, int index)
540         {
541             if (array == null)
542             {
543                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("array");
544             }
545
546             if (index < 0 || (index + headerCount) > array.Length)
547             {
548                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
549                     new ArgumentOutOfRangeException("index", index,
550                     SR.GetString(SR.ValueMustBeInRange, 0, array.Length - headerCount)));
551             }
552             for (int i = 0; i < headerCount; i++)
553                 array[i + index] = headers[i].HeaderInfo;
554         }
555
556         Exception CreateDuplicateHeaderException(HeaderKind kind)
557         {
558             string name;
559             switch (kind)
560             {
561                 case HeaderKind.Action:
562                     name = AddressingStrings.Action;
563                     break;
564                 case HeaderKind.FaultTo:
565                     name = AddressingStrings.FaultTo;
566                     break;
567                 case HeaderKind.From:
568                     name = AddressingStrings.From;
569                     break;
570                 case HeaderKind.MessageId:
571                     name = AddressingStrings.MessageId;
572                     break;
573                 case HeaderKind.ReplyTo:
574                     name = AddressingStrings.ReplyTo;
575                     break;
576                 case HeaderKind.To:
577                     name = AddressingStrings.To;
578                     break;
579                 default:
580                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, kind)));
581             }
582
583             return new MessageHeaderException(
584                 SR.GetString(SR.MultipleMessageHeaders, name, this.version.Addressing.Namespace),
585                 name,
586                 this.version.Addressing.Namespace,
587                 true);
588         }
589
590         public int FindHeader(string name, string ns)
591         {
592             if (name == null)
593                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
594             if (ns == null)
595                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
596
597             if (ns == this.version.Addressing.Namespace)
598             {
599                 return FindAddressingHeader(name, ns);
600             }
601             else
602             {
603                 return FindNonAddressingHeader(name, ns, version.Envelope.UltimateDestinationActorValues);
604             }
605         }
606
607         int FindAddressingHeader(string name, string ns)
608         {
609             int foundAt = -1;
610             for (int i = 0; i < headerCount; i++)
611             {
612                 if (headers[i].HeaderKind != HeaderKind.Unknown)
613                 {
614                     MessageHeaderInfo info = headers[i].HeaderInfo;
615                     if (info.Name == name && info.Namespace == ns)
616                     {
617                         if (foundAt >= 0)
618                         {
619                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
620                                 new MessageHeaderException(SR.GetString(SR.MultipleMessageHeaders, name, ns), name, ns, true));
621                         }
622                         foundAt = i;
623                     }
624                 }
625             }
626             return foundAt;
627         }
628
629         int FindNonAddressingHeader(string name, string ns, string[] actors)
630         {
631             int foundAt = -1;
632             for (int i = 0; i < headerCount; i++)
633             {
634                 if (headers[i].HeaderKind == HeaderKind.Unknown)
635                 {
636                     MessageHeaderInfo info = headers[i].HeaderInfo;
637                     if (info.Name == name && info.Namespace == ns)
638                     {
639                         for (int j = 0; j < actors.Length; j++)
640                         {
641                             if (actors[j] == info.Actor)
642                             {
643                                 if (foundAt >= 0)
644                                 {
645                                     if (actors.Length == 1)
646                                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeadersWithActor, name, ns, actors[0]), name, ns, true));
647                                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeaders, name, ns), name, ns, true));
648                                 }
649                                 foundAt = i;
650                             }
651                         }
652                     }
653                 }
654             }
655             return foundAt;
656         }
657
658         public int FindHeader(string name, string ns, params string[] actors)
659         {
660             if (name == null)
661                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
662             if (ns == null)
663                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
664             if (actors == null)
665                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("actors"));
666             int foundAt = -1;
667             for (int i = 0; i < headerCount; i++)
668             {
669                 MessageHeaderInfo info = headers[i].HeaderInfo;
670                 if (info.Name == name && info.Namespace == ns)
671                 {
672                     for (int j = 0; j < actors.Length; j++)
673                     {
674                         if (actors[j] == info.Actor)
675                         {
676                             if (foundAt >= 0)
677                             {
678                                 if (actors.Length == 1)
679                                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeadersWithActor, name, ns, actors[0]), name, ns, true));
680                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.MultipleMessageHeaders, name, ns), name, ns, true));
681                             }
682                             foundAt = i;
683                         }
684                     }
685                 }
686             }
687             return foundAt;
688         }
689
690         int FindHeaderProperty(HeaderKind kind)
691         {
692             int index = -1;
693             for (int i = 0; i < headerCount; i++)
694             {
695                 if (headers[i].HeaderKind == kind)
696                 {
697                     if (index >= 0)
698                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateDuplicateHeaderException(kind));
699                     index = i;
700                 }
701             }
702             return index;
703         }
704
705         int FindRelatesTo(Uri relationshipType, out UniqueId messageId)
706         {
707             UniqueId foundValue = null;
708             int foundIndex = -1;
709             for (int i = 0; i < headerCount; i++)
710             {
711                 if (headers[i].HeaderKind == HeaderKind.RelatesTo)
712                 {
713                     Uri tempRelationship;
714                     UniqueId tempValue;
715                     GetRelatesToValues(i, out tempRelationship, out tempValue);
716
717                     if (relationshipType == tempRelationship)
718                     {
719                         if (foundValue != null)
720                         {
721                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
722                                 new MessageHeaderException(
723                                     SR.GetString(SR.MultipleRelatesToHeaders, relationshipType.AbsoluteUri),
724                                     AddressingStrings.RelatesTo,
725                                     this.version.Addressing.Namespace,
726                                     true));
727                         }
728                         foundValue = tempValue;
729                         foundIndex = i;
730                     }
731                 }
732             }
733
734             messageId = foundValue;
735             return foundIndex;
736         }
737
738         IEnumerator IEnumerable.GetEnumerator()
739         {
740             return this.GetEnumerator();
741         }
742
743         public IEnumerator<MessageHeaderInfo> GetEnumerator()
744         {
745             MessageHeaderInfo[] headers = new MessageHeaderInfo[headerCount];
746             CopyTo(headers, 0);
747             return GetEnumerator(headers);
748         }
749
750         IEnumerator<MessageHeaderInfo> GetEnumerator(MessageHeaderInfo[] headers)
751         {
752             IList<MessageHeaderInfo> list = Array.AsReadOnly<MessageHeaderInfo>(headers);
753             return list.GetEnumerator();
754         }
755
756         internal IEnumerator<MessageHeaderInfo> GetUnderstoodEnumerator()
757         {
758             List<MessageHeaderInfo> understoodHeaders = new List<MessageHeaderInfo>();
759
760             for (int i = 0; i < headerCount; i++)
761             {
762                 if ((headers[i].HeaderProcessing & HeaderProcessing.Understood) != 0)
763                 {
764                     understoodHeaders.Add(headers[i].HeaderInfo);
765                 }
766             }
767
768             return understoodHeaders.GetEnumerator();
769         }
770
771         static XmlDictionaryReader GetBufferedMessageHeaderReaderAtHeaderContents(IBufferedMessageData bufferedMessageData)
772         {
773             XmlDictionaryReader reader = bufferedMessageData.GetMessageReader();
774             if (reader.NodeType == XmlNodeType.Element)
775                 reader.Read();
776             else
777                 reader.ReadStartElement();
778             if (reader.NodeType == XmlNodeType.Element)
779                 reader.Read();
780             else
781                 reader.ReadStartElement();
782             return reader;
783         }
784
785         XmlDictionaryReader GetBufferedMessageHeaderReader(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex)
786         {
787             // Check if we need to change representations
788             if (this.nodeCount > MaxBufferedHeaderNodes || this.attrCount > MaxBufferedHeaderAttributes)
789             {
790                 CaptureBufferedHeaders();
791                 return headers[bufferedMessageHeaderIndex].ReadableHeader.GetHeaderReader();
792             }
793
794             XmlDictionaryReader reader = GetBufferedMessageHeaderReaderAtHeaderContents(bufferedMessageData);
795             for (;;)
796             {
797                 if (reader.NodeType != XmlNodeType.Element)
798                     reader.MoveToContent();
799                 if (bufferedMessageHeaderIndex == 0)
800                     break;
801                 Skip(reader);
802                 bufferedMessageHeaderIndex--;
803             }
804
805             return reader;
806         }
807
808         void Skip(XmlDictionaryReader reader)
809         {
810             if (reader.MoveToContent() == XmlNodeType.Element && !reader.IsEmptyElement)
811             {
812                 int depth = reader.Depth;
813                 do
814                 {
815                     this.attrCount += reader.AttributeCount;
816                     this.nodeCount++;
817                 } while (reader.Read() && depth < reader.Depth);
818
819                 // consume end tag
820                 if (reader.NodeType == XmlNodeType.EndElement)
821                 {
822                     this.nodeCount++;
823                     reader.Read();
824                 }
825             }
826             else
827             {
828                 this.attrCount += reader.AttributeCount;
829                 this.nodeCount++;
830                 reader.Read();
831             }
832         }
833
834         public T GetHeader<T>(string name, string ns)
835         {
836             return GetHeader<T>(name, ns, DataContractSerializerDefaults.CreateSerializer(typeof(T), name, ns, int.MaxValue/*maxItems*/));
837         }
838
839         public T GetHeader<T>(string name, string ns, params string[] actors)
840         {
841             int index = FindHeader(name, ns, actors);
842             if (index < 0)
843                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.HeaderNotFound, name, ns), name, ns));
844             return GetHeader<T>(index);
845
846         }
847
848         public T GetHeader<T>(string name, string ns, XmlObjectSerializer serializer)
849         {
850             if (serializer == null)
851                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
852             int index = FindHeader(name, ns);
853             if (index < 0)
854                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString(SR.HeaderNotFound, name, ns), name, ns));
855             return GetHeader<T>(index, serializer);
856         }
857
858         public T GetHeader<T>(int index)
859         {
860             if (index < 0 || index >= headerCount)
861             {
862                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
863                     new ArgumentOutOfRangeException("index", index,
864                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
865             }
866
867             MessageHeaderInfo headerInfo = headers[index].HeaderInfo;
868             return GetHeader<T>(index, DataContractSerializerDefaults.CreateSerializer(typeof(T), headerInfo.Name, headerInfo.Namespace, int.MaxValue/*maxItems*/));
869         }
870
871         public T GetHeader<T>(int index, XmlObjectSerializer serializer)
872         {
873             if (serializer == null)
874                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
875             using (XmlDictionaryReader reader = GetReaderAtHeader(index))
876             {
877                 return (T)serializer.ReadObject(reader);
878             }
879         }
880
881         HeaderKind GetHeaderKind(MessageHeaderInfo headerInfo)
882         {
883             HeaderKind headerKind = HeaderKind.Unknown;
884
885             if (headerInfo.Namespace == this.version.Addressing.Namespace)
886             {
887                 if (version.Envelope.IsUltimateDestinationActor(headerInfo.Actor))
888                 {
889                     string name = headerInfo.Name;
890                     if (name.Length > 0)
891                     {
892                         switch (name[0])
893                         {
894                             case 'A':
895                                 if (name == AddressingStrings.Action)
896                                 {
897                                     headerKind = HeaderKind.Action;
898                                 }
899                                 break;
900                             case 'F':
901                                 if (name == AddressingStrings.From)
902                                 {
903                                     headerKind = HeaderKind.From;
904                                 }
905                                 else if (name == AddressingStrings.FaultTo)
906                                 {
907                                     headerKind = HeaderKind.FaultTo;
908                                 }
909                                 break;
910                             case 'M':
911                                 if (name == AddressingStrings.MessageId)
912                                 {
913                                     headerKind = HeaderKind.MessageId;
914                                 }
915                                 break;
916                             case 'R':
917                                 if (name == AddressingStrings.ReplyTo)
918                                 {
919                                     headerKind = HeaderKind.ReplyTo;
920                                 }
921                                 else if (name == AddressingStrings.RelatesTo)
922                                 {
923                                     headerKind = HeaderKind.RelatesTo;
924                                 }
925                                 break;
926                             case 'T':
927                                 if (name == AddressingStrings.To)
928                                 {
929                                     headerKind = HeaderKind.To;
930                                 }
931                                 break;
932                         }
933                     }
934                 }
935             }
936
937             ValidateHeaderKind(headerKind);
938             return headerKind;
939         }
940
941         void ValidateHeaderKind(HeaderKind headerKind)
942         {
943             if (this.version.Envelope == EnvelopeVersion.None)
944             {
945                 if (headerKind != HeaderKind.Action && headerKind != HeaderKind.To)
946                 {
947                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
948                         new InvalidOperationException(SR.GetString(SR.HeadersCannotBeAddedToEnvelopeVersion, this.version.Envelope)));
949                 }
950             }
951
952             if (this.version.Addressing == AddressingVersion.None)
953             {
954                 if (headerKind != HeaderKind.Unknown && headerKind != HeaderKind.Action && headerKind != HeaderKind.To)
955                 {
956                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
957                         new InvalidOperationException(SR.GetString(SR.AddressingHeadersCannotBeAddedToAddressingVersion, this.version.Addressing)));
958                 }
959             }
960         }
961
962         public XmlDictionaryReader GetReaderAtHeader(int headerIndex)
963         {
964             if (headerIndex < 0 || headerIndex >= headerCount)
965             {
966                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
967                     new ArgumentOutOfRangeException("headerIndex", headerIndex,
968                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
969             }
970
971             switch (headers[headerIndex].HeaderType)
972             {
973                 case HeaderType.ReadableHeader:
974                     return headers[headerIndex].ReadableHeader.GetHeaderReader();
975                 case HeaderType.WriteableHeader:
976                     MessageHeader writeableHeader = headers[headerIndex].MessageHeader;
977                     BufferedHeader bufferedHeader = CaptureWriteableHeader(writeableHeader);
978                     headers[headerIndex] = new Header(headers[headerIndex].HeaderKind, bufferedHeader, headers[headerIndex].HeaderProcessing);
979                     collectionVersion++;
980                     return bufferedHeader.GetHeaderReader();
981                 case HeaderType.BufferedMessageHeader:
982                     return GetBufferedMessageHeaderReader(bufferedMessageData, headerIndex);
983                 default:
984                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[headerIndex].HeaderType)));
985             }
986         }
987
988         internal UniqueId GetRelatesTo(Uri relationshipType)
989         {
990             if (relationshipType == null)
991                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("relationshipType"));
992
993             UniqueId messageId;
994             FindRelatesTo(relationshipType, out messageId);
995             return messageId;
996         }
997
998         void GetRelatesToValues(int index, out Uri relationshipType, out UniqueId messageId)
999         {
1000             RelatesToHeader relatesToHeader = headers[index].HeaderInfo as RelatesToHeader;
1001             if (relatesToHeader != null)
1002             {
1003                 relationshipType = relatesToHeader.RelationshipType;
1004                 messageId = relatesToHeader.UniqueId;
1005             }
1006             else
1007             {
1008                 using (XmlDictionaryReader reader = GetReaderAtHeader(index))
1009                 {
1010                     RelatesToHeader.ReadHeaderValue(reader, version.Addressing, out relationshipType, out messageId);
1011                 }
1012             }
1013         }
1014
1015         internal string[] GetHeaderAttributes(string localName, string ns)
1016         {
1017             string[] attrs = null;
1018
1019             if (ContainsOnlyBufferedMessageHeaders)
1020             {
1021                 XmlDictionaryReader reader = bufferedMessageData.GetMessageReader();
1022                 reader.ReadStartElement(); // Envelope
1023                 reader.ReadStartElement(); // Header
1024                 for (int index = 0; reader.IsStartElement(); index++)
1025                 {
1026                     string value = reader.GetAttribute(localName, ns);
1027                     if (value != null)
1028                     {
1029                         if (attrs == null)
1030                             attrs = new string[headerCount];
1031                         attrs[index] = value;
1032                     }
1033                     if (index == headerCount - 1)
1034                         break;
1035                     reader.Skip();
1036                 }
1037                 reader.Close();
1038             }
1039             else
1040             {
1041                 for (int index = 0; index < headerCount; index++)
1042                 {
1043                     if (headers[index].HeaderType != HeaderType.WriteableHeader)
1044                     {
1045                         using (XmlDictionaryReader reader = GetReaderAtHeader(index))
1046                         {
1047                             string value = reader.GetAttribute(localName, ns);
1048                             if (value != null)
1049                             {
1050                                 if (attrs == null)
1051                                     attrs = new string[headerCount];
1052                                 attrs[index] = value;
1053                             }
1054                         }
1055                     }
1056                 }
1057             }
1058
1059             return attrs;
1060         }
1061
1062         internal MessageHeader GetMessageHeader(int index)
1063         {
1064             if (index < 0 || index >= headerCount)
1065             {
1066                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1067                     new ArgumentOutOfRangeException("headerIndex", index,
1068                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
1069             }
1070             MessageHeader messageHeader;
1071             switch (headers[index].HeaderType)
1072             {
1073                 case HeaderType.WriteableHeader:
1074                 case HeaderType.ReadableHeader:
1075                     return headers[index].MessageHeader;
1076                 case HeaderType.BufferedMessageHeader:
1077                     messageHeader = CaptureBufferedHeader(bufferedMessageData, headers[index].HeaderInfo, index);
1078                     headers[index] = new Header(headers[index].HeaderKind, messageHeader, headers[index].HeaderProcessing);
1079                     collectionVersion++;
1080                     return messageHeader;
1081                 default:
1082                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[index].HeaderType)));
1083             }
1084         }
1085
1086         internal Collection<MessageHeaderInfo> GetHeadersNotUnderstood()
1087         {
1088             Collection<MessageHeaderInfo> notUnderstoodHeaders = null;
1089
1090             for (int headerIndex = 0; headerIndex < headerCount; headerIndex++)
1091             {
1092                 if (headers[headerIndex].HeaderProcessing == HeaderProcessing.MustUnderstand)
1093                 {
1094                     if (notUnderstoodHeaders == null)
1095                         notUnderstoodHeaders = new Collection<MessageHeaderInfo>();
1096
1097                     MessageHeaderInfo headerInfo = headers[headerIndex].HeaderInfo;
1098                     if (DiagnosticUtility.ShouldTraceWarning)
1099                     {
1100                         TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.DidNotUnderstandMessageHeader,
1101                             SR.GetString(SR.TraceCodeDidNotUnderstandMessageHeader),
1102                             new MessageHeaderInfoTraceRecord(headerInfo), null, null);
1103                     }
1104
1105                     notUnderstoodHeaders.Add(headerInfo);
1106                 }
1107             }
1108
1109             return notUnderstoodHeaders;
1110         }
1111
1112         public bool HaveMandatoryHeadersBeenUnderstood()
1113         {
1114             return HaveMandatoryHeadersBeenUnderstood(version.Envelope.MustUnderstandActorValues);
1115         }
1116
1117         public bool HaveMandatoryHeadersBeenUnderstood(params string[] actors)
1118         {
1119             if (actors == null)
1120                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("actors"));
1121
1122             for (int headerIndex = 0; headerIndex < headerCount; headerIndex++)
1123             {
1124                 if (headers[headerIndex].HeaderProcessing == HeaderProcessing.MustUnderstand)
1125                 {
1126                     for (int actorIndex = 0; actorIndex < actors.Length; ++actorIndex)
1127                     {
1128                         if (headers[headerIndex].HeaderInfo.Actor == actors[actorIndex])
1129                         {
1130                             return false;
1131                         }
1132                     }
1133                 }
1134             }
1135
1136             return true;
1137         }
1138
1139         internal void Init(MessageVersion version, int initialSize)
1140         {
1141             this.nodeCount = 0;
1142             this.attrCount = 0;
1143             if (initialSize < 0)
1144             {
1145                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1146                     new ArgumentOutOfRangeException("initialSize", initialSize,
1147                     SR.GetString(SR.ValueMustBeNonNegative)));
1148             }
1149
1150             if (version == null)
1151             {
1152                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
1153             }
1154
1155             this.version = version;
1156             headers = new Header[initialSize];
1157         }
1158
1159         internal void Init(MessageVersion version)
1160         {
1161             this.nodeCount = 0;
1162             this.attrCount = 0;
1163             this.version = version;
1164             this.collectionVersion = 0;
1165         }
1166
1167         internal void Init(MessageVersion version, XmlDictionaryReader reader, IBufferedMessageData bufferedMessageData, RecycledMessageState recycledMessageState, bool[] understoodHeaders, bool understoodHeadersModified)
1168         {
1169             this.nodeCount = 0;
1170             this.attrCount = 0;
1171             this.version = version;
1172             this.bufferedMessageData = bufferedMessageData;
1173
1174             if (version.Envelope != EnvelopeVersion.None)
1175             {
1176                 this.understoodHeadersModified = (understoodHeaders != null) && understoodHeadersModified;
1177                 if (reader.IsEmptyElement)
1178                 {
1179                     reader.Read();
1180                     return;
1181                 }
1182                 EnvelopeVersion envelopeVersion = version.Envelope;
1183                 Fx.Assert(reader.IsStartElement(XD.MessageDictionary.Header, envelopeVersion.DictionaryNamespace), "");
1184                 reader.ReadStartElement();
1185
1186                 AddressingDictionary dictionary = XD.AddressingDictionary;
1187
1188                 if (localNames == null)
1189                 {
1190                     XmlDictionaryString[] strings = new XmlDictionaryString[7];
1191                     strings[(int)HeaderKind.To] = dictionary.To;
1192                     strings[(int)HeaderKind.Action] = dictionary.Action;
1193                     strings[(int)HeaderKind.MessageId] = dictionary.MessageId;
1194                     strings[(int)HeaderKind.RelatesTo] = dictionary.RelatesTo;
1195                     strings[(int)HeaderKind.ReplyTo] = dictionary.ReplyTo;
1196                     strings[(int)HeaderKind.From] = dictionary.From;
1197                     strings[(int)HeaderKind.FaultTo] = dictionary.FaultTo;
1198                     System.Threading.Thread.MemoryBarrier();
1199                     localNames = strings;
1200                 }
1201
1202
1203                 int i = 0;
1204                 while (reader.IsStartElement())
1205                 {
1206                     ReadBufferedHeader(reader, recycledMessageState, localNames, (understoodHeaders == null) ? false : understoodHeaders[i++]);
1207                 }
1208
1209                 reader.ReadEndElement();
1210             }
1211             this.collectionVersion = 0;
1212         }
1213
1214         public void Insert(int headerIndex, MessageHeader header)
1215         {
1216             if (header == null)
1217                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("header"));
1218             if (!header.IsMessageVersionSupported(this.version))
1219                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MessageHeaderVersionNotSupported,
1220                     header.GetType().FullName, this.version.Envelope.ToString()), "header"));
1221             Insert(headerIndex, header, GetHeaderKind(header));
1222         }
1223
1224         void Insert(int headerIndex, MessageHeader header, HeaderKind kind)
1225         {
1226             ReadableMessageHeader readableMessageHeader = header as ReadableMessageHeader;
1227             HeaderProcessing processing = header.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
1228             if (kind != HeaderKind.Unknown)
1229                 processing |= HeaderProcessing.Understood;
1230             if (readableMessageHeader != null)
1231                 InsertHeader(headerIndex, new Header(kind, readableMessageHeader, processing));
1232             else
1233                 InsertHeader(headerIndex, new Header(kind, header, processing));
1234         }
1235
1236         void InsertHeader(int headerIndex, Header header)
1237         {
1238             ValidateHeaderKind(header.HeaderKind);
1239
1240             if (headerIndex < 0 || headerIndex > headerCount)
1241             {
1242                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1243                     new ArgumentOutOfRangeException("headerIndex", headerIndex,
1244                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
1245             }
1246
1247             if (headerCount == headers.Length)
1248             {
1249                 if (headers.Length == 0)
1250                 {
1251                     headers = new Header[1];
1252                 }
1253                 else
1254                 {
1255                     Header[] newHeaders = new Header[headers.Length * 2];
1256                     headers.CopyTo(newHeaders, 0);
1257                     headers = newHeaders;
1258                 }
1259             }
1260             if (headerIndex < headerCount)
1261             {
1262                 if (bufferedMessageData != null)
1263                 {
1264                     for (int i = headerIndex; i < headerCount; i++)
1265                     {
1266                         if (headers[i].HeaderType == HeaderType.BufferedMessageHeader)
1267                         {
1268                             CaptureBufferedHeaders();
1269                             break;
1270                         }
1271                     }
1272                 }
1273                 Array.Copy(headers, headerIndex, headers, headerIndex + 1, headerCount - headerIndex);
1274             }
1275             headers[headerIndex] = header;
1276             headerCount++;
1277             collectionVersion++;
1278         }
1279
1280         internal bool IsUnderstood(int i)
1281         {
1282             return (headers[i].HeaderProcessing & HeaderProcessing.Understood) != 0;
1283         }
1284
1285         internal bool IsUnderstood(MessageHeaderInfo headerInfo)
1286         {
1287             if (headerInfo == null)
1288                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("headerInfo"));
1289             for (int i = 0; i < headerCount; i++)
1290             {
1291                 if ((object)headers[i].HeaderInfo == (object)headerInfo)
1292                 {
1293                     if (IsUnderstood(i))
1294                         return true;
1295                 }
1296             }
1297
1298             return false;
1299         }
1300
1301         void ReadBufferedHeader(XmlDictionaryReader reader, RecycledMessageState recycledMessageState, XmlDictionaryString[] localNames, bool understood)
1302         {
1303             string actor;
1304             bool mustUnderstand;
1305             bool relay;
1306             bool isRefParam;
1307
1308             if (this.version.Addressing == AddressingVersion.None && reader.NamespaceURI == AddressingVersion.None.Namespace)
1309             {
1310                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1311                     new InvalidOperationException(SR.GetString(SR.AddressingHeadersCannotBeAddedToAddressingVersion, this.version.Addressing)));
1312             }
1313
1314             MessageHeader.GetHeaderAttributes(reader, version, out actor, out mustUnderstand, out relay, out isRefParam);
1315
1316             HeaderKind kind = HeaderKind.Unknown;
1317             MessageHeaderInfo info = null;
1318
1319             if (version.Envelope.IsUltimateDestinationActor(actor))
1320             {
1321                 Fx.Assert(version.Addressing.DictionaryNamespace != null, "non-None Addressing requires a non-null DictionaryNamespace");
1322                 kind = (HeaderKind)reader.IndexOfLocalName(localNames, version.Addressing.DictionaryNamespace);
1323                 switch (kind)
1324                 {
1325                     case HeaderKind.To:
1326                         info = ToHeader.ReadHeader(reader, version.Addressing, recycledMessageState.UriCache, actor, mustUnderstand, relay);
1327                         break;
1328                     case HeaderKind.Action:
1329                         info = ActionHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
1330                         break;
1331                     case HeaderKind.MessageId:
1332                         info = MessageIDHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
1333                         break;
1334                     case HeaderKind.RelatesTo:
1335                         info = RelatesToHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
1336                         break;
1337                     case HeaderKind.ReplyTo:
1338                         info = ReplyToHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
1339                         break;
1340                     case HeaderKind.From:
1341                         info = FromHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
1342                         break;
1343                     case HeaderKind.FaultTo:
1344                         info = FaultToHeader.ReadHeader(reader, version.Addressing, actor, mustUnderstand, relay);
1345                         break;
1346                     default:
1347                         kind = HeaderKind.Unknown;
1348                         break;
1349                 }
1350             }
1351
1352             if (info == null)
1353             {
1354                 info = recycledMessageState.HeaderInfoCache.TakeHeaderInfo(reader, actor, mustUnderstand, relay, isRefParam);
1355                 reader.Skip();
1356             }
1357
1358             HeaderProcessing processing = mustUnderstand ? HeaderProcessing.MustUnderstand : 0;
1359             if (kind != HeaderKind.Unknown || understood)
1360             {
1361                 processing |= HeaderProcessing.Understood;
1362                 MessageHeaders.TraceUnderstood(info);
1363             }
1364             AddHeader(new Header(kind, info, processing));
1365         }
1366
1367         internal void Recycle(HeaderInfoCache headerInfoCache)
1368         {
1369             for (int i = 0; i < headerCount; i++)
1370             {
1371                 if (headers[i].HeaderKind == HeaderKind.Unknown)
1372                 {
1373                     headerInfoCache.ReturnHeaderInfo(headers[i].HeaderInfo);
1374                 }
1375             }
1376             Clear();
1377             collectionVersion = 0;
1378             if (understoodHeaders != null)
1379             {
1380                 understoodHeaders.Modified = false;
1381             }
1382         }
1383
1384         internal void RemoveUnderstood(MessageHeaderInfo headerInfo)
1385         {
1386             if (headerInfo == null)
1387                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("headerInfo"));
1388             for (int i = 0; i < headerCount; i++)
1389             {
1390                 if ((object)headers[i].HeaderInfo == (object)headerInfo)
1391                 {
1392                     if ((headers[i].HeaderProcessing & HeaderProcessing.Understood) == 0)
1393                     {
1394                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(
1395                             SR.GetString(SR.HeaderAlreadyNotUnderstood, headerInfo.Name, headerInfo.Namespace), "headerInfo"));
1396                     }
1397
1398                     headers[i].HeaderProcessing &= ~HeaderProcessing.Understood;
1399                 }
1400             }
1401         }
1402
1403         public void RemoveAll(string name, string ns)
1404         {
1405             if (name == null)
1406                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("name"));
1407             if (ns == null)
1408                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("ns"));
1409             for (int i = headerCount - 1; i >= 0; i--)
1410             {
1411                 MessageHeaderInfo info = headers[i].HeaderInfo;
1412                 if (info.Name == name && info.Namespace == ns)
1413                 {
1414                     RemoveAt(i);
1415                 }
1416             }
1417         }
1418
1419         public void RemoveAt(int headerIndex)
1420         {
1421             if (headerIndex < 0 || headerIndex >= headerCount)
1422             {
1423                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1424                     new ArgumentOutOfRangeException("headerIndex", headerIndex,
1425                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
1426             }
1427             if (bufferedMessageData != null && headers[headerIndex].HeaderType == HeaderType.BufferedMessageHeader)
1428                 CaptureBufferedHeaders(headerIndex);
1429             Array.Copy(headers, headerIndex + 1, headers, headerIndex, headerCount - headerIndex - 1);
1430             headers[--headerCount] = new Header();
1431             collectionVersion++;
1432         }
1433
1434         internal void ReplaceAt(int headerIndex, MessageHeader header)
1435         {
1436             if (headerIndex < 0 || headerIndex >= headerCount)
1437             {
1438                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1439                     new ArgumentOutOfRangeException("headerIndex", headerIndex,
1440                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
1441             }
1442
1443             if (header == null)
1444             {
1445                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("header");
1446             }
1447
1448             ReplaceAt(headerIndex, header, GetHeaderKind(header));
1449         }
1450
1451         void ReplaceAt(int headerIndex, MessageHeader header, HeaderKind kind)
1452         {
1453             HeaderProcessing processing = header.MustUnderstand ? HeaderProcessing.MustUnderstand : 0;
1454             if (kind != HeaderKind.Unknown)
1455                 processing |= HeaderProcessing.Understood;
1456             ReadableMessageHeader readableMessageHeader = header as ReadableMessageHeader;
1457             if (readableMessageHeader != null)
1458                 headers[headerIndex] = new Header(kind, readableMessageHeader, processing);
1459             else
1460                 headers[headerIndex] = new Header(kind, header, processing);
1461             collectionVersion++;
1462         }
1463
1464         public void SetAction(XmlDictionaryString action)
1465         {
1466             if (action == null)
1467                 SetHeaderProperty(HeaderKind.Action, null);
1468             else
1469                 SetActionHeader(ActionHeader.Create(action, version.Addressing));
1470         }
1471
1472         internal void SetActionHeader(ActionHeader actionHeader)
1473         {
1474             SetHeaderProperty(HeaderKind.Action, actionHeader);
1475         }
1476
1477         internal void SetFaultToHeader(FaultToHeader faultToHeader)
1478         {
1479             SetHeaderProperty(HeaderKind.FaultTo, faultToHeader);
1480         }
1481
1482         internal void SetFromHeader(FromHeader fromHeader)
1483         {
1484             SetHeaderProperty(HeaderKind.From, fromHeader);
1485         }
1486
1487         internal void SetMessageIDHeader(MessageIDHeader messageIDHeader)
1488         {
1489             SetHeaderProperty(HeaderKind.MessageId, messageIDHeader);
1490         }
1491
1492         internal void SetRelatesTo(Uri relationshipType, UniqueId messageId)
1493         {
1494             if (relationshipType == null)
1495             {
1496                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("relationshipType");
1497             }
1498
1499             RelatesToHeader relatesToHeader;
1500             if (!object.ReferenceEquals(messageId, null))
1501             {
1502                 relatesToHeader = RelatesToHeader.Create(messageId, version.Addressing, relationshipType);
1503             }
1504             else
1505             {
1506                 relatesToHeader = null;
1507             }
1508
1509             SetRelatesTo(RelatesToHeader.ReplyRelationshipType, relatesToHeader);
1510         }
1511
1512         void SetRelatesTo(Uri relationshipType, RelatesToHeader relatesToHeader)
1513         {
1514             UniqueId previousUniqueId;
1515             int index = FindRelatesTo(relationshipType, out previousUniqueId);
1516             if (index >= 0)
1517             {
1518                 if (relatesToHeader == null)
1519                 {
1520                     RemoveAt(index);
1521                 }
1522                 else
1523                 {
1524                     ReplaceAt(index, relatesToHeader, HeaderKind.RelatesTo);
1525                 }
1526             }
1527             else if (relatesToHeader != null)
1528             {
1529                 Add(relatesToHeader, HeaderKind.RelatesTo);
1530             }
1531         }
1532
1533         internal void SetReplyToHeader(ReplyToHeader replyToHeader)
1534         {
1535             SetHeaderProperty(HeaderKind.ReplyTo, replyToHeader);
1536         }
1537
1538         internal void SetToHeader(ToHeader toHeader)
1539         {
1540             SetHeaderProperty(HeaderKind.To, toHeader);
1541         }
1542
1543         void SetHeaderProperty(HeaderKind kind, MessageHeader header)
1544         {
1545             int index = FindHeaderProperty(kind);
1546             if (index >= 0)
1547             {
1548                 if (header == null)
1549                 {
1550                     RemoveAt(index);
1551                 }
1552                 else
1553                 {
1554                     ReplaceAt(index, header, kind);
1555                 }
1556             }
1557             else if (header != null)
1558             {
1559                 Add(header, kind);
1560             }
1561         }
1562
1563         public void WriteHeader(int headerIndex, XmlWriter writer)
1564         {
1565             WriteHeader(headerIndex, XmlDictionaryWriter.CreateDictionaryWriter(writer));
1566         }
1567
1568         public void WriteHeader(int headerIndex, XmlDictionaryWriter writer)
1569         {
1570             WriteStartHeader(headerIndex, writer);
1571             WriteHeaderContents(headerIndex, writer);
1572             writer.WriteEndElement();
1573         }
1574
1575         public void WriteStartHeader(int headerIndex, XmlWriter writer)
1576         {
1577             WriteStartHeader(headerIndex, XmlDictionaryWriter.CreateDictionaryWriter(writer));
1578         }
1579
1580         public void WriteStartHeader(int headerIndex, XmlDictionaryWriter writer)
1581         {
1582             if (writer == null)
1583             {
1584                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
1585             }
1586
1587             if (headerIndex < 0 || headerIndex >= headerCount)
1588             {
1589                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1590                     new ArgumentOutOfRangeException("headerIndex", headerIndex,
1591                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
1592             }
1593             switch (headers[headerIndex].HeaderType)
1594             {
1595                 case HeaderType.ReadableHeader:
1596                 case HeaderType.WriteableHeader:
1597                     headers[headerIndex].MessageHeader.WriteStartHeader(writer, this.version);
1598                     break;
1599                 case HeaderType.BufferedMessageHeader:
1600                     WriteStartBufferedMessageHeader(bufferedMessageData, headerIndex, writer);
1601                     break;
1602                 default:
1603                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[headerIndex].HeaderType)));
1604             }
1605         }
1606
1607         public void WriteHeaderContents(int headerIndex, XmlWriter writer)
1608         {
1609             WriteHeaderContents(headerIndex, XmlDictionaryWriter.CreateDictionaryWriter(writer));
1610         }
1611
1612         public void WriteHeaderContents(int headerIndex, XmlDictionaryWriter writer)
1613         {
1614             if (writer == null)
1615             {
1616                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
1617             }
1618
1619             if (headerIndex < 0 || headerIndex >= headerCount)
1620             {
1621                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1622                     new ArgumentOutOfRangeException("headerIndex", headerIndex,
1623                     SR.GetString(SR.ValueMustBeInRange, 0, headerCount)));
1624             }
1625             switch (headers[headerIndex].HeaderType)
1626             {
1627                 case HeaderType.ReadableHeader:
1628                 case HeaderType.WriteableHeader:
1629                     headers[headerIndex].MessageHeader.WriteHeaderContents(writer, this.version);
1630                     break;
1631                 case HeaderType.BufferedMessageHeader:
1632                     WriteBufferedMessageHeaderContents(bufferedMessageData, headerIndex, writer);
1633                     break;
1634                 default:
1635                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidEnumValue, headers[headerIndex].HeaderType)));
1636             }
1637         }
1638
1639         static void TraceUnderstood(MessageHeaderInfo info)
1640         {
1641             if (DiagnosticUtility.ShouldTraceVerbose)
1642             {
1643                 TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.UnderstoodMessageHeader,
1644                     SR.GetString(SR.TraceCodeUnderstoodMessageHeader),
1645                     new MessageHeaderInfoTraceRecord(info), null, null);
1646             }
1647         }
1648
1649         void WriteBufferedMessageHeader(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex, XmlWriter writer)
1650         {
1651             using (XmlReader reader = GetBufferedMessageHeaderReader(bufferedMessageData, bufferedMessageHeaderIndex))
1652             {
1653                 writer.WriteNode(reader, false);
1654             }
1655         }
1656
1657         void WriteStartBufferedMessageHeader(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex, XmlWriter writer)
1658         {
1659             using (XmlReader reader = GetBufferedMessageHeaderReader(bufferedMessageData, bufferedMessageHeaderIndex))
1660             {
1661                 writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
1662                 writer.WriteAttributes(reader, false);
1663             }
1664         }
1665
1666         void WriteBufferedMessageHeaderContents(IBufferedMessageData bufferedMessageData, int bufferedMessageHeaderIndex, XmlWriter writer)
1667         {
1668             using (XmlReader reader = GetBufferedMessageHeaderReader(bufferedMessageData, bufferedMessageHeaderIndex))
1669             {
1670                 if (!reader.IsEmptyElement)
1671                 {
1672                     reader.ReadStartElement();
1673                     while (reader.NodeType != XmlNodeType.EndElement)
1674                     {
1675                         writer.WriteNode(reader, false);
1676                     }
1677                     reader.ReadEndElement();
1678                 }
1679             }
1680         }
1681
1682         enum HeaderType : byte
1683         {
1684             Invalid,
1685             ReadableHeader,
1686             BufferedMessageHeader,
1687             WriteableHeader
1688         }
1689
1690         enum HeaderKind : byte
1691         {
1692             Action,
1693             FaultTo,
1694             From,
1695             MessageId,
1696             ReplyTo,
1697             RelatesTo,
1698             To,
1699             Unknown,
1700         }
1701
1702         [Flags]
1703         enum HeaderProcessing : byte
1704         {
1705             MustUnderstand = 0x1,
1706             Understood = 0x2,
1707         }
1708
1709         struct Header
1710         {
1711             HeaderType type;
1712             HeaderKind kind;
1713             HeaderProcessing processing;
1714             MessageHeaderInfo info;
1715
1716             public Header(HeaderKind kind, MessageHeaderInfo info, HeaderProcessing processing)
1717             {
1718                 this.kind = kind;
1719                 this.type = HeaderType.BufferedMessageHeader;
1720                 this.info = info;
1721                 this.processing = processing;
1722             }
1723
1724             public Header(HeaderKind kind, ReadableMessageHeader readableHeader, HeaderProcessing processing)
1725             {
1726                 this.kind = kind;
1727                 this.type = HeaderType.ReadableHeader;
1728                 this.info = readableHeader;
1729                 this.processing = processing;
1730             }
1731
1732             public Header(HeaderKind kind, MessageHeader header, HeaderProcessing processing)
1733             {
1734                 this.kind = kind;
1735                 this.type = HeaderType.WriteableHeader;
1736                 this.info = header;
1737                 this.processing = processing;
1738             }
1739
1740             public HeaderType HeaderType
1741             {
1742                 get { return type; }
1743             }
1744
1745             public HeaderKind HeaderKind
1746             {
1747                 get { return kind; }
1748             }
1749
1750             public MessageHeaderInfo HeaderInfo
1751             {
1752                 get { return info; }
1753             }
1754
1755             public MessageHeader MessageHeader
1756             {
1757                 get
1758                 {
1759                     Fx.Assert(type == HeaderType.WriteableHeader || type == HeaderType.ReadableHeader, "");
1760                     return (MessageHeader)info;
1761                 }
1762             }
1763
1764             public HeaderProcessing HeaderProcessing
1765             {
1766                 get { return processing; }
1767                 set { processing = value; }
1768             }
1769
1770             public ReadableMessageHeader ReadableHeader
1771             {
1772                 get
1773                 {
1774                     Fx.Assert(type == HeaderType.ReadableHeader, "");
1775                     return (ReadableMessageHeader)info;
1776                 }
1777             }
1778         }
1779     }
1780 }