Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / Message.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.ServiceModel.Channels
6 {
7     using System.Collections.Generic;
8     using System.Diagnostics;
9     using System.Globalization;
10     using System.IO;
11     using System.Runtime;
12     using System.Runtime.Serialization;
13     using System.ServiceModel;
14     using System.ServiceModel.Diagnostics;
15     using System.ServiceModel.Dispatcher;
16     using System.Threading;
17     using System.Xml;
18
19     public abstract class Message : IDisposable
20     {
21         MessageState state;
22         SeekableMessageNavigator messageNavigator;
23         internal const int InitialBufferSize = 1024;
24
25         public abstract MessageHeaders Headers { get; } // must never return null
26
27         protected bool IsDisposed
28         {
29             get { return state == MessageState.Closed; }
30         }
31
32         public virtual bool IsFault
33         {
34             get
35             {
36                 if (IsDisposed)
37 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
38                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
39
40                 return false;
41             }
42         }
43
44         public virtual bool IsEmpty
45         {
46             get
47             {
48                 if (IsDisposed)
49 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
50                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
51
52                 return false;
53             }
54         }
55
56         public abstract MessageProperties Properties { get; }
57
58         public abstract MessageVersion Version { get; } // must never return null
59
60         internal virtual void SetProperty(string name, object value)
61         {
62             MessageProperties prop = Properties;
63
64             if (prop != null)
65             {
66                 prop[name] = value;
67             }
68         }
69
70         internal virtual bool GetProperty(string name, out object result)
71         {
72             MessageProperties prop = Properties;
73
74             if (prop != null)
75             {
76                 return prop.TryGetValue(name, out result);
77             }
78
79             result = null;
80             return false;
81         }
82
83         internal virtual RecycledMessageState RecycledMessageState
84         {
85             get { return null; }
86         }
87
88         public MessageState State
89         {
90             get { return state; }
91         }
92
93         internal void BodyToString(XmlDictionaryWriter writer)
94         {
95             OnBodyToString(writer);
96         }
97
98         public void Close()
99         {
100             if (state != MessageState.Closed)
101             {
102                 state = MessageState.Closed;
103                 OnClose();
104                 if (DiagnosticUtility.ShouldTraceVerbose)
105                 {
106                     TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageClosed,
107                         SR.GetString(SR.TraceCodeMessageClosed), this);
108                 }
109             }
110             else
111             {
112                 if (DiagnosticUtility.ShouldTraceVerbose)
113                 {
114                     TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageClosedAgain,
115                         SR.GetString(SR.TraceCodeMessageClosedAgain), this);
116                 }
117             }
118         }
119
120         public MessageBuffer CreateBufferedCopy(int maxBufferSize)
121         {
122             if (maxBufferSize < 0)
123                 throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", maxBufferSize,
124                                                     SR.GetString(SR.ValueMustBeNonNegative)), this);
125             switch (state)
126             {
127                 case MessageState.Created:
128                     state = MessageState.Copied;
129                     if (DiagnosticUtility.ShouldTraceVerbose)
130                     {
131                         TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageCopied,
132                             SR.GetString(SR.TraceCodeMessageCopied), this, this);
133                     }
134                     break;
135                 case MessageState.Closed:
136                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
137                 case MessageState.Copied:
138                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this);
139                 case MessageState.Read:
140                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this);
141                 case MessageState.Written:
142                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this);
143                 default:
144                     Fx.Assert(SR.GetString(SR.InvalidMessageState));
145                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this);
146             }
147             return OnCreateBufferedCopy(maxBufferSize);
148         }
149
150         static Type GetObjectType(object value)
151         {
152             return (value == null) ? typeof(object) : value.GetType();
153         }
154
155         static public Message CreateMessage(MessageVersion version, string action, object body)
156         {
157             return CreateMessage(version, action, body, DataContractSerializerDefaults.CreateSerializer(GetObjectType(body), int.MaxValue/*maxItems*/));
158         }
159
160         static public Message CreateMessage(MessageVersion version, string action, object body, XmlObjectSerializer serializer)
161         {
162             if (version == null)
163                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
164             if (serializer == null)
165                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
166             return new BodyWriterMessage(version, action, new XmlObjectSerializerBodyWriter(body, serializer));
167         }
168
169         static public Message CreateMessage(MessageVersion version, string action, XmlReader body)
170         {
171             return CreateMessage(version, action, XmlDictionaryReader.CreateDictionaryReader(body));
172         }
173
174         static public Message CreateMessage(MessageVersion version, string action, XmlDictionaryReader body)
175         {
176             if (body == null)
177                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("body");
178             if (version == null)
179                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
180
181             return CreateMessage(version, action, new XmlReaderBodyWriter(body, version.Envelope));
182         }
183
184         static public Message CreateMessage(MessageVersion version, string action, BodyWriter body)
185         {
186             if (version == null)
187                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
188             if (body == null)
189                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("body"));
190             return new BodyWriterMessage(version, action, body);
191         }
192
193         static internal Message CreateMessage(MessageVersion version, ActionHeader actionHeader, BodyWriter body)
194         {
195             if (version == null)
196                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
197             if (body == null)
198                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("body"));
199             return new BodyWriterMessage(version, actionHeader, body);
200         }
201
202         static public Message CreateMessage(MessageVersion version, string action)
203         {
204             if (version == null)
205                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
206             return new BodyWriterMessage(version, action, EmptyBodyWriter.Value);
207         }
208
209         static internal Message CreateMessage(MessageVersion version, ActionHeader actionHeader)
210         {
211             if (version == null)
212                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
213             return new BodyWriterMessage(version, actionHeader, EmptyBodyWriter.Value);
214         }
215
216         static public Message CreateMessage(XmlReader envelopeReader, int maxSizeOfHeaders, MessageVersion version)
217         {
218             return CreateMessage(XmlDictionaryReader.CreateDictionaryReader(envelopeReader), maxSizeOfHeaders, version);
219         }
220
221         static public Message CreateMessage(XmlDictionaryReader envelopeReader, int maxSizeOfHeaders, MessageVersion version)
222         {
223             if (envelopeReader == null)
224                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("envelopeReader"));
225             if (version == null)
226                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
227             Message message = new StreamedMessage(envelopeReader, maxSizeOfHeaders, version);
228             return message;
229         }
230
231         static public Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, string action)
232         {
233             if (version == null)
234                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
235             if (faultCode == null)
236                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("faultCode"));
237             if (reason == null)
238                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reason"));
239
240             return CreateMessage(version, MessageFault.CreateFault(faultCode, reason), action);
241         }
242
243         static public Message CreateMessage(MessageVersion version, FaultCode faultCode, string reason, object detail, string action)
244         {
245             if (version == null)
246                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
247             if (faultCode == null)
248                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("faultCode"));
249             if (reason == null)
250                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("reason"));
251
252             return CreateMessage(version, MessageFault.CreateFault(faultCode, new FaultReason(reason), detail), action);
253         }
254
255         static public Message CreateMessage(MessageVersion version, MessageFault fault, string action)
256         {
257             if (fault == null)
258                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("fault"));
259             if (version == null)
260                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("version"));
261             return new BodyWriterMessage(version, action, new FaultBodyWriter(fault, version.Envelope));
262         }
263
264         internal Exception CreateMessageDisposedException()
265         {
266             return new ObjectDisposedException("", SR.GetString(SR.MessageClosed));
267         }
268
269         void IDisposable.Dispose()
270         {
271             Close();
272         }
273
274         public T GetBody<T>()
275         {
276             XmlDictionaryReader reader = GetReaderAtBodyContents();   // This call will change the message state to Read.
277             return OnGetBody<T>(reader);
278         }
279
280         protected virtual T OnGetBody<T>(XmlDictionaryReader reader)
281         {
282             return this.GetBodyCore<T>(reader, DataContractSerializerDefaults.CreateSerializer(typeof(T), int.MaxValue/*maxItems*/));
283         }
284
285         public T GetBody<T>(XmlObjectSerializer serializer)
286         {
287             if (serializer == null)
288                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serializer"));
289             return this.GetBodyCore<T>(GetReaderAtBodyContents(), serializer);
290         }
291
292         T GetBodyCore<T>(XmlDictionaryReader reader, XmlObjectSerializer serializer)
293         {
294             T value;
295             using (reader)
296             {
297                 value = (T)serializer.ReadObject(reader);
298                 this.ReadFromBodyContentsToEnd(reader);
299             }
300             return value;
301         }
302
303         internal virtual XmlDictionaryReader GetReaderAtHeader()
304         {
305             XmlBuffer buffer = new XmlBuffer(int.MaxValue);
306             XmlDictionaryWriter writer = buffer.OpenSection(XmlDictionaryReaderQuotas.Max);
307             WriteStartEnvelope(writer);
308             MessageHeaders headers = this.Headers;
309             for (int i = 0; i < headers.Count; i++)
310                 headers.WriteHeader(i, writer);
311             writer.WriteEndElement();
312             writer.WriteEndElement();
313             buffer.CloseSection();
314             buffer.Close();
315             XmlDictionaryReader reader = buffer.GetReader(0);
316             reader.ReadStartElement();
317             reader.MoveToStartElement();
318             return reader;
319         }
320
321         public XmlDictionaryReader GetReaderAtBodyContents()
322         {
323             EnsureReadMessageState();
324             if (IsEmpty)
325                 throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageIsEmpty)), this);
326             return OnGetReaderAtBodyContents();
327         }
328
329         internal void EnsureReadMessageState()
330         {
331             switch (state)
332             {
333                 case MessageState.Created:
334                     state = MessageState.Read;
335                     if (DiagnosticUtility.ShouldTraceVerbose)
336                     {
337                         TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageRead, SR.GetString(SR.TraceCodeMessageRead), this);
338                     }
339                     break;
340                 case MessageState.Copied:
341                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this);
342                 case MessageState.Read:
343                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this);
344                 case MessageState.Written:
345                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this);
346                 case MessageState.Closed:
347                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
348                 default:
349                     Fx.Assert(SR.GetString(SR.InvalidMessageState));
350                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this);
351             }
352         }
353
354         internal SeekableMessageNavigator GetNavigator(bool navigateBody, int maxNodes)
355         {
356             if (IsDisposed)
357                 throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
358             if (null == this.messageNavigator)
359             {
360                 this.messageNavigator = new SeekableMessageNavigator(this, maxNodes, XmlSpace.Default, navigateBody, false);
361             }
362             else
363             {
364                 this.messageNavigator.ForkNodeCount(maxNodes);
365             }
366
367             return this.messageNavigator;
368         }
369
370         internal void InitializeReply(Message request)
371         {
372             UniqueId requestMessageID = request.Headers.MessageId;
373             if (requestMessageID == null)
374                 throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.RequestMessageDoesNotHaveAMessageID)), request);
375             Headers.RelatesTo = requestMessageID;
376         }
377
378         static internal bool IsFaultStartElement(XmlDictionaryReader reader, EnvelopeVersion version)
379         {
380             return reader.IsStartElement(XD.MessageDictionary.Fault, version.DictionaryNamespace);
381         }
382
383         protected virtual void OnBodyToString(XmlDictionaryWriter writer)
384         {
385             writer.WriteString(SR.GetString(SR.MessageBodyIsUnknown));
386         }
387
388         protected virtual MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
389         {
390             return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max);
391         }
392
393         internal MessageBuffer OnCreateBufferedCopy(int maxBufferSize, XmlDictionaryReaderQuotas quotas)
394         {
395             XmlBuffer msgBuffer = new XmlBuffer(maxBufferSize);
396             XmlDictionaryWriter writer = msgBuffer.OpenSection(quotas);
397             OnWriteMessage(writer);
398             msgBuffer.CloseSection();
399             msgBuffer.Close();
400             return new DefaultMessageBuffer(this, msgBuffer);
401         }
402
403         protected virtual void OnClose()
404         {
405         }
406
407         protected virtual XmlDictionaryReader OnGetReaderAtBodyContents()
408         {
409             XmlBuffer bodyBuffer = new XmlBuffer(int.MaxValue);
410             XmlDictionaryWriter writer = bodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
411             if (this.Version.Envelope != EnvelopeVersion.None)
412             {
413                 OnWriteStartEnvelope(writer);
414                 OnWriteStartBody(writer);
415             }
416             OnWriteBodyContents(writer);
417             if (this.Version.Envelope != EnvelopeVersion.None)
418             {
419                 writer.WriteEndElement();
420                 writer.WriteEndElement();
421             }
422             bodyBuffer.CloseSection();
423             bodyBuffer.Close();
424             XmlDictionaryReader reader = bodyBuffer.GetReader(0);
425             if (this.Version.Envelope != EnvelopeVersion.None)
426             {
427                 reader.ReadStartElement();
428                 reader.ReadStartElement();
429             }
430             reader.MoveToContent();
431             return reader;
432         }
433
434         protected virtual void OnWriteStartBody(XmlDictionaryWriter writer)
435         {
436             MessageDictionary messageDictionary = XD.MessageDictionary;
437             writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Body, Version.Envelope.DictionaryNamespace);
438         }
439
440         public void WriteBodyContents(XmlDictionaryWriter writer)
441         {
442             EnsureWriteMessageState(writer);
443             OnWriteBodyContents(writer);
444         }
445
446         public IAsyncResult BeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
447         {
448             EnsureWriteMessageState(writer);
449             return this.OnBeginWriteBodyContents(writer, callback, state);
450         }
451
452         public void EndWriteBodyContents(IAsyncResult result)
453         {
454             this.OnEndWriteBodyContents(result);
455         }
456
457         protected abstract void OnWriteBodyContents(XmlDictionaryWriter writer);
458
459         protected virtual IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
460         {
461             return new OnWriteBodyContentsAsyncResult(writer, this, callback, state);
462         }
463
464         protected virtual void OnEndWriteBodyContents(IAsyncResult result)
465         {
466             OnWriteBodyContentsAsyncResult.End(result);
467         }
468
469         public void WriteStartEnvelope(XmlDictionaryWriter writer)
470         {
471             if (writer == null)
472                 throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
473
474             OnWriteStartEnvelope(writer);
475         }
476
477         protected virtual void OnWriteStartEnvelope(XmlDictionaryWriter writer)
478         {
479             EnvelopeVersion envelopeVersion = Version.Envelope;
480             if (envelopeVersion != EnvelopeVersion.None)
481             {
482                 MessageDictionary messageDictionary = XD.MessageDictionary;
483                 writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Envelope, envelopeVersion.DictionaryNamespace);
484                 WriteSharedHeaderPrefixes(writer);
485             }
486         }
487
488         protected virtual void OnWriteStartHeaders(XmlDictionaryWriter writer)
489         {
490             EnvelopeVersion envelopeVersion = Version.Envelope;
491             if (envelopeVersion != EnvelopeVersion.None)
492             {
493                 MessageDictionary messageDictionary = XD.MessageDictionary;
494                 writer.WriteStartElement(messageDictionary.Prefix.Value, messageDictionary.Header, envelopeVersion.DictionaryNamespace);
495             }
496         }
497
498         public override string ToString()
499         {
500             if (IsDisposed)
501             {
502                 return base.ToString();
503             }
504
505             StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
506             EncodingFallbackAwareXmlTextWriter textWriter = new EncodingFallbackAwareXmlTextWriter(stringWriter);
507             textWriter.Formatting = Formatting.Indented;
508             XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(textWriter);
509             try
510             {
511                 ToString(writer);
512                 writer.Flush();
513                 return stringWriter.ToString();
514             }
515             catch (XmlException e)
516             {
517                 return SR.GetString(SR.MessageBodyToStringError, e.GetType().ToString(), e.Message);
518             }
519         }
520
521         internal void ToString(XmlDictionaryWriter writer)
522         {
523             if (IsDisposed)
524             {
525                 throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
526             }
527
528             if (this.Version.Envelope != EnvelopeVersion.None)
529             {
530                 WriteStartEnvelope(writer);
531                 WriteStartHeaders(writer);
532                 MessageHeaders headers = this.Headers;
533                 for (int i = 0; i < headers.Count; i++)
534                 {
535                     headers.WriteHeader(i, writer);
536                 }
537
538                 writer.WriteEndElement();
539                 MessageDictionary messageDictionary = XD.MessageDictionary;
540                 WriteStartBody(writer);
541             }
542
543             BodyToString(writer);
544
545             if (this.Version.Envelope != EnvelopeVersion.None)
546             {
547                 writer.WriteEndElement();
548                 writer.WriteEndElement();
549             }
550         }
551
552         public string GetBodyAttribute(string localName, string ns)
553         {
554             if (localName == null)
555                 throw TraceUtility.ThrowHelperError(new ArgumentNullException("localName"), this);
556             if (ns == null)
557                 throw TraceUtility.ThrowHelperError(new ArgumentNullException("ns"), this);
558             switch (state)
559             {
560                 case MessageState.Created:
561                     break;
562                 case MessageState.Copied:
563                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this);
564                 case MessageState.Read:
565                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this);
566                 case MessageState.Written:
567                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this);
568                 case MessageState.Closed:
569                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
570                 default:
571                     Fx.Assert(SR.GetString(SR.InvalidMessageState));
572                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this);
573             }
574             return OnGetBodyAttribute(localName, ns);
575         }
576
577         protected virtual string OnGetBodyAttribute(string localName, string ns)
578         {
579             return null;
580         }
581
582         internal void ReadFromBodyContentsToEnd(XmlDictionaryReader reader)
583         {
584             Message.ReadFromBodyContentsToEnd(reader, this.Version.Envelope);
585         }
586
587         static void ReadFromBodyContentsToEnd(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion)
588         {
589             if (envelopeVersion != EnvelopeVersion.None)
590             {
591                 reader.ReadEndElement(); // </Body>
592                 reader.ReadEndElement(); // </Envelope>
593             }
594             reader.MoveToContent();
595         }
596
597         internal static bool ReadStartBody(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion, out bool isFault, out bool isEmpty)
598         {
599             if (reader.IsEmptyElement)
600             {
601                 reader.Read();
602                 isEmpty = true;
603                 isFault = false;
604                 reader.ReadEndElement();
605                 return false;
606             }
607             else
608             {
609                 reader.Read();
610                 if (reader.NodeType != XmlNodeType.Element)
611                     reader.MoveToContent();
612                 if (reader.NodeType == XmlNodeType.Element)
613                 {
614                     isFault = IsFaultStartElement(reader, envelopeVersion);
615                     isEmpty = false;
616                 }
617                 else if (reader.NodeType == XmlNodeType.EndElement)
618                 {
619                     isEmpty = true;
620                     isFault = false;
621                     Message.ReadFromBodyContentsToEnd(reader, envelopeVersion);
622                     return false;
623                 }
624                 else
625                 {
626                     isEmpty = false;
627                     isFault = false;
628                 }
629
630                 return true;
631             }
632         }
633
634         public void WriteBody(XmlWriter writer)
635         {
636             WriteBody(XmlDictionaryWriter.CreateDictionaryWriter(writer));
637         }
638
639         public void WriteBody(XmlDictionaryWriter writer)
640         {
641             WriteStartBody(writer);
642             WriteBodyContents(writer);
643             writer.WriteEndElement();
644         }
645
646         public void WriteStartBody(XmlWriter writer)
647         {
648             WriteStartBody(XmlDictionaryWriter.CreateDictionaryWriter(writer));
649         }
650
651         public void WriteStartBody(XmlDictionaryWriter writer)
652         {
653             if (writer == null)
654                 throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
655             OnWriteStartBody(writer);
656         }
657
658         internal void WriteStartHeaders(XmlDictionaryWriter writer)
659         {
660             OnWriteStartHeaders(writer);
661         }
662
663         public void WriteMessage(XmlWriter writer)
664         {
665             WriteMessage(XmlDictionaryWriter.CreateDictionaryWriter(writer));
666         }
667
668         public void WriteMessage(XmlDictionaryWriter writer)
669         {
670             EnsureWriteMessageState(writer);
671             OnWriteMessage(writer);
672         }
673
674         void EnsureWriteMessageState(XmlDictionaryWriter writer)
675         {
676             if (writer == null)
677                 throw TraceUtility.ThrowHelperError(new ArgumentNullException("writer"), this);
678             switch (state)
679             {
680                 case MessageState.Created:
681                     state = MessageState.Written;
682                     if (DiagnosticUtility.ShouldTraceVerbose)
683                     {
684                         TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.MessageWritten, SR.GetString(SR.TraceCodeMessageWritten), this);
685                     }
686                     break;
687                 case MessageState.Copied:
688                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenCopied)), this);
689                 case MessageState.Read:
690                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenRead)), this);
691                 case MessageState.Written:
692                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageHasBeenWritten)), this);
693                 case MessageState.Closed:
694                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
695                 default:
696                     Fx.Assert(SR.GetString(SR.InvalidMessageState));
697                     throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidMessageState)), this);
698             }
699         }
700
701         public IAsyncResult BeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state)
702         {
703             EnsureWriteMessageState(writer);
704             return OnBeginWriteMessage(writer, callback, state);
705         }
706
707         public void EndWriteMessage(IAsyncResult result)
708         {
709             OnEndWriteMessage(result);
710         }
711
712         protected virtual void OnWriteMessage(XmlDictionaryWriter writer)
713         {
714             WriteMessagePreamble(writer);
715             OnWriteBodyContents(writer);
716             WriteMessagePostamble(writer);
717         }
718
719         internal void WriteMessagePreamble(XmlDictionaryWriter writer)
720         {
721             if (this.Version.Envelope != EnvelopeVersion.None)
722             {
723                 OnWriteStartEnvelope(writer);
724
725                 MessageHeaders headers = this.Headers;
726                 int headersCount = headers.Count;
727                 if (headersCount > 0)
728                 {
729                     OnWriteStartHeaders(writer);
730                     for (int i = 0; i < headersCount; i++)
731                     {
732                         headers.WriteHeader(i, writer);
733                     }
734                     writer.WriteEndElement();
735                 }
736
737                 OnWriteStartBody(writer);
738             }
739         }
740
741         internal void WriteMessagePostamble(XmlDictionaryWriter writer)
742         {
743             if (this.Version.Envelope != EnvelopeVersion.None)
744             {
745                 writer.WriteEndElement();
746                 writer.WriteEndElement();
747             }
748         }
749
750         protected virtual IAsyncResult OnBeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state)
751         {
752             return new OnWriteMessageAsyncResult(writer, this, callback, state);
753         }
754
755         protected virtual void OnEndWriteMessage(IAsyncResult result)
756         {
757             OnWriteMessageAsyncResult.End(result);
758         }
759
760         void WriteSharedHeaderPrefixes(XmlDictionaryWriter writer)
761         {
762             MessageHeaders headers = Headers;
763             int count = headers.Count;
764             int prefixesWritten = 0;
765             for (int i = 0; i < count; i++)
766             {
767                 if (this.Version.Addressing == AddressingVersion.None && headers[i].Namespace == AddressingVersion.None.Namespace)
768                 {
769                     continue;
770                 }
771
772                 IMessageHeaderWithSharedNamespace headerWithSharedNamespace = headers[i] as IMessageHeaderWithSharedNamespace;
773                 if (headerWithSharedNamespace != null)
774                 {
775                     XmlDictionaryString prefix = headerWithSharedNamespace.SharedPrefix;
776                     string prefixString = prefix.Value;
777                     if (!((prefixString.Length == 1)))
778                     {
779                         Fx.Assert("Message.WriteSharedHeaderPrefixes: (prefixString.Length == 1) -- IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.");
780                         throw TraceUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.")), this);
781                     }
782
783                     int prefixIndex = prefixString[0] - 'a';
784                     if (!((prefixIndex >= 0 && prefixIndex < 26)))
785                     {
786                         Fx.Assert("Message.WriteSharedHeaderPrefixes: (prefixIndex >= 0 && prefixIndex < 26) -- IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.");
787                         throw TraceUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "IMessageHeaderWithSharedNamespace must use a single lowercase letter prefix.")), this);
788                     }
789                     int prefixBit = 1 << prefixIndex;
790                     if ((prefixesWritten & prefixBit) == 0)
791                     {
792                         writer.WriteXmlnsAttribute(prefixString, headerWithSharedNamespace.SharedNamespace);
793                         prefixesWritten |= prefixBit;
794                     }
795                 }
796             }
797         }
798
799         class OnWriteBodyContentsAsyncResult : ScheduleActionItemAsyncResult
800         {
801             Message message;
802             XmlDictionaryWriter writer;
803
804             public OnWriteBodyContentsAsyncResult(XmlDictionaryWriter writer, Message message, AsyncCallback callback, object state)
805                 : base(callback, state)
806             {
807                 Fx.Assert(message != null, "message should never be null");
808
809                 this.message = message;
810                 this.writer = writer;
811
812                 Schedule();
813             }
814
815             protected override void OnDoWork()
816             {
817                 this.message.OnWriteBodyContents(this.writer);
818             }
819         }
820
821         class OnWriteMessageAsyncResult : ScheduleActionItemAsyncResult
822         {
823             Message message;
824             XmlDictionaryWriter writer;
825
826             public OnWriteMessageAsyncResult(XmlDictionaryWriter writer, Message message, AsyncCallback callback, object state)
827                 : base(callback, state)
828             {
829                 Fx.Assert(message != null, "message should never be null");
830
831                 this.message = message;
832                 this.writer = writer;
833
834                 Schedule();
835             }
836
837             protected override void OnDoWork()
838             {
839                 this.message.OnWriteMessage(this.writer);
840             }
841         }
842     }
843
844     class EmptyBodyWriter : BodyWriter
845     {
846         static EmptyBodyWriter value;
847
848         EmptyBodyWriter()
849             : base(true)
850         {
851         }
852
853         public static EmptyBodyWriter Value
854         {
855             get
856             {
857                 if (value == null)
858                     value = new EmptyBodyWriter();
859                 return value;
860             }
861         }
862
863         internal override bool IsEmpty
864         {
865             get { return true; }
866         }
867
868         protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
869         {
870         }
871     }
872
873     class FaultBodyWriter : BodyWriter
874     {
875         MessageFault fault;
876         EnvelopeVersion version;
877
878         public FaultBodyWriter(MessageFault fault, EnvelopeVersion version)
879             : base(true)
880         {
881             this.fault = fault;
882             this.version = version;
883         }
884
885         internal override bool IsFault
886         {
887             get { return true; }
888         }
889
890         protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
891         {
892             fault.WriteTo(writer, version);
893         }
894     }
895
896     class XmlObjectSerializerBodyWriter : BodyWriter
897     {
898         object body;
899         XmlObjectSerializer serializer;
900
901         public XmlObjectSerializerBodyWriter(object body, XmlObjectSerializer serializer)
902             : base(true)
903         {
904             this.body = body;
905             this.serializer = serializer;
906         }
907
908         object ThisLock
909         {
910             get { return this; }
911         }
912
913         protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
914         {
915             lock (ThisLock)
916             {
917                 serializer.WriteObject(writer, body);
918             }
919         }
920     }
921
922     class XmlReaderBodyWriter : BodyWriter
923     {
924         XmlDictionaryReader reader;
925         bool isFault;
926
927         public XmlReaderBodyWriter(XmlDictionaryReader reader, EnvelopeVersion version)
928             : base(false)
929         {
930             this.reader = reader;
931             if (reader.MoveToContent() != XmlNodeType.Element)
932                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidReaderPositionOnCreateMessage), "reader"));
933
934             this.isFault = Message.IsFaultStartElement(reader, version);
935         }
936
937         internal override bool IsFault
938         {
939             get
940             {
941                 return this.isFault;
942             }
943         }
944
945         protected override BodyWriter OnCreateBufferedCopy(int maxBufferSize)
946         {
947             return OnCreateBufferedCopy(maxBufferSize, this.reader.Quotas);
948         }
949
950         protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
951         {
952             using (reader)
953             {
954                 XmlNodeType type = reader.MoveToContent();
955                 while (!reader.EOF && type != XmlNodeType.EndElement)
956                 {
957                     if (type != XmlNodeType.Element)
958                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidReaderPositionOnCreateMessage), "reader"));
959                     writer.WriteNode(reader, false);
960
961                     type = reader.MoveToContent();
962                 }
963             }
964         }
965     }
966
967     class BodyWriterMessage : Message
968     {
969         MessageProperties properties;
970         MessageHeaders headers;
971         BodyWriter bodyWriter;
972
973         BodyWriterMessage(BodyWriter bodyWriter)
974         {
975             this.bodyWriter = bodyWriter;
976         }
977
978         public BodyWriterMessage(MessageVersion version, string action, BodyWriter bodyWriter)
979             : this(bodyWriter)
980         {
981             this.headers = new MessageHeaders(version);
982             this.headers.Action = action;
983         }
984
985         public BodyWriterMessage(MessageVersion version, ActionHeader actionHeader, BodyWriter bodyWriter)
986             : this(bodyWriter)
987         {
988             this.headers = new MessageHeaders(version);
989             this.headers.SetActionHeader(actionHeader);
990         }
991
992         public BodyWriterMessage(MessageHeaders headers, KeyValuePair<string, object>[] properties, BodyWriter bodyWriter)
993             : this(bodyWriter)
994         {
995             this.headers = new MessageHeaders(headers);
996             this.properties = new MessageProperties(properties);
997         }
998
999         public override bool IsFault
1000         {
1001             get
1002             {
1003                 if (IsDisposed)
1004 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1005                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1006                 return bodyWriter.IsFault;
1007             }
1008         }
1009
1010         public override bool IsEmpty
1011         {
1012             get
1013             {
1014                 if (IsDisposed)
1015 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1016                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1017                 return bodyWriter.IsEmpty;
1018             }
1019         }
1020
1021         public override MessageHeaders Headers
1022         {
1023             get
1024             {
1025                 if (IsDisposed)
1026 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1027                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1028                 return headers;
1029             }
1030         }
1031
1032         public override MessageProperties Properties
1033         {
1034             get
1035             {
1036                 if (IsDisposed)
1037 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1038                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1039                 if (properties == null)
1040                     properties = new MessageProperties();
1041                 return properties;
1042             }
1043         }
1044
1045         internal override void SetProperty(string name, object value)
1046         {
1047             MessageProperties prop = this.properties;
1048
1049             if (prop != null)
1050             {
1051                 prop[name] = value;
1052             }
1053         }
1054
1055         internal override bool GetProperty(string name, out object result)
1056         {
1057             MessageProperties prop = this.properties;
1058
1059             if (prop != null)
1060             {
1061                 return prop.TryGetValue(name, out result);
1062             }
1063
1064             result = null;
1065             return false;
1066         }
1067
1068
1069         public override MessageVersion Version
1070         {
1071             get
1072             {
1073                 if (IsDisposed)
1074 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1075                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1076                 return headers.MessageVersion;
1077             }
1078         }
1079
1080         protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
1081         {
1082             BodyWriter bufferedBodyWriter;
1083             if (bodyWriter.IsBuffered)
1084             {
1085                 bufferedBodyWriter = bodyWriter;
1086             }
1087             else
1088             {
1089                 bufferedBodyWriter = bodyWriter.CreateBufferedCopy(maxBufferSize);
1090             }
1091             KeyValuePair<string, object>[] properties = new KeyValuePair<string, object>[Properties.Count];
1092             ((ICollection<KeyValuePair<string, object>>)Properties).CopyTo(properties, 0);
1093             return new BodyWriterMessageBuffer(headers, properties, bufferedBodyWriter);
1094         }
1095
1096         protected override void OnClose()
1097         {
1098             Exception ex = null;
1099             try
1100             {
1101                 base.OnClose();
1102             }
1103             catch (Exception e)
1104             {
1105                 if (Fx.IsFatal(e))
1106                     throw;
1107                 ex = e;
1108             }
1109
1110             try
1111             {
1112                 if (properties != null)
1113                     properties.Dispose();
1114             }
1115             catch (Exception e)
1116             {
1117                 if (Fx.IsFatal(e))
1118                     throw;
1119                 if (ex == null)
1120                     ex = e;
1121             }
1122
1123             if (ex != null)
1124                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex);
1125
1126             bodyWriter = null;
1127         }
1128
1129         protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
1130         {
1131             bodyWriter.WriteBodyContents(writer);
1132         }
1133
1134         protected override IAsyncResult OnBeginWriteMessage(XmlDictionaryWriter writer, AsyncCallback callback, object state)
1135         {
1136             WriteMessagePreamble(writer);
1137             return new OnWriteMessageAsyncResult(writer, this, callback, state);
1138         }
1139
1140         protected override void OnEndWriteMessage(IAsyncResult result)
1141         {
1142             OnWriteMessageAsyncResult.End(result);
1143         }
1144
1145         protected override IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
1146         {
1147             return bodyWriter.BeginWriteBodyContents(writer, callback, state);
1148         }
1149
1150         protected override void OnEndWriteBodyContents(IAsyncResult result)
1151         {
1152             bodyWriter.EndWriteBodyContents(result);
1153         }
1154
1155         protected override void OnBodyToString(XmlDictionaryWriter writer)
1156         {
1157             if (bodyWriter.IsBuffered)
1158             {
1159                 bodyWriter.WriteBodyContents(writer);
1160             }
1161             else
1162             {
1163                 writer.WriteString(SR.GetString(SR.MessageBodyIsStream));
1164             }
1165         }
1166
1167         protected internal BodyWriter BodyWriter
1168         {
1169             get
1170             {
1171                 return bodyWriter;
1172             }
1173         }
1174
1175         class OnWriteMessageAsyncResult : AsyncResult
1176         {
1177             BodyWriterMessage message;
1178             XmlDictionaryWriter writer;
1179
1180             public OnWriteMessageAsyncResult(XmlDictionaryWriter writer, BodyWriterMessage message, AsyncCallback callback, object state)
1181                 : base(callback, state)
1182             {
1183                 this.message = message;
1184                 this.writer = writer;
1185
1186                 if (HandleWriteBodyContents(null))
1187                 {
1188                     this.Complete(true);
1189                 }
1190             }
1191
1192             bool HandleWriteBodyContents(IAsyncResult result)
1193             {
1194                 if (result == null)
1195                 {
1196                     result = this.message.OnBeginWriteBodyContents(this.writer, PrepareAsyncCompletion(HandleWriteBodyContents), this);
1197                     if (!result.CompletedSynchronously)
1198                     {
1199                         return false;
1200                     }
1201                 }
1202
1203                 this.message.OnEndWriteBodyContents(result);
1204                 this.message.WriteMessagePostamble(this.writer);
1205                 return true;
1206             }
1207
1208             public static void End(IAsyncResult result)
1209             {
1210                 AsyncResult.End<OnWriteMessageAsyncResult>(result);
1211             }
1212         }
1213
1214     }
1215
1216     abstract class ReceivedMessage : Message
1217     {
1218         bool isFault;
1219         bool isEmpty;
1220
1221         public override bool IsEmpty
1222         {
1223             get { return isEmpty; }
1224         }
1225
1226         public override bool IsFault
1227         {
1228             get { return isFault; }
1229         }
1230
1231         protected static bool HasHeaderElement(XmlDictionaryReader reader, EnvelopeVersion envelopeVersion)
1232         {
1233             return reader.IsStartElement(XD.MessageDictionary.Header, envelopeVersion.DictionaryNamespace);
1234         }
1235
1236         protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
1237         {
1238             if (!isEmpty)
1239             {
1240                 using (XmlDictionaryReader bodyReader = OnGetReaderAtBodyContents())
1241                 {
1242                     if (bodyReader.ReadState == ReadState.Error || bodyReader.ReadState == ReadState.Closed)
1243                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MessageBodyReaderInvalidReadState, bodyReader.ReadState.ToString())));
1244
1245                     while (bodyReader.NodeType != XmlNodeType.EndElement && !bodyReader.EOF)
1246                     {
1247                         writer.WriteNode(bodyReader, false);
1248                     }
1249
1250                     this.ReadFromBodyContentsToEnd(bodyReader);
1251                 }
1252             }
1253         }
1254
1255         protected bool ReadStartBody(XmlDictionaryReader reader)
1256         {
1257             return Message.ReadStartBody(reader, this.Version.Envelope, out this.isFault, out this.isEmpty);
1258         }
1259
1260         protected static EnvelopeVersion ReadStartEnvelope(XmlDictionaryReader reader)
1261         {
1262             EnvelopeVersion envelopeVersion;
1263
1264             if (reader.IsStartElement(XD.MessageDictionary.Envelope, XD.Message12Dictionary.Namespace))
1265                 envelopeVersion = EnvelopeVersion.Soap12;
1266             else if (reader.IsStartElement(XD.MessageDictionary.Envelope, XD.Message11Dictionary.Namespace))
1267                 envelopeVersion = EnvelopeVersion.Soap11;
1268             else
1269                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageVersionUnknown)));
1270             if (reader.IsEmptyElement)
1271                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageBodyMissing)));
1272             reader.Read();
1273             return envelopeVersion;
1274         }
1275
1276         protected static void VerifyStartBody(XmlDictionaryReader reader, EnvelopeVersion version)
1277         {
1278             if (!reader.IsStartElement(XD.MessageDictionary.Body, version.DictionaryNamespace))
1279                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.MessageBodyMissing)));
1280         }
1281     }
1282
1283     sealed class StreamedMessage : ReceivedMessage
1284     {
1285         MessageHeaders headers;
1286         XmlAttributeHolder[] envelopeAttributes;
1287         XmlAttributeHolder[] headerAttributes;
1288         XmlAttributeHolder[] bodyAttributes;
1289         string envelopePrefix;
1290         string headerPrefix;
1291         string bodyPrefix;
1292         MessageProperties properties;
1293         XmlDictionaryReader reader;
1294         XmlDictionaryReaderQuotas quotas;
1295
1296         public StreamedMessage(XmlDictionaryReader reader, int maxSizeOfHeaders, MessageVersion desiredVersion)
1297         {
1298             properties = new MessageProperties();
1299             if (reader.NodeType != XmlNodeType.Element)
1300                 reader.MoveToContent();
1301
1302             if (desiredVersion.Envelope == EnvelopeVersion.None)
1303             {
1304                 this.reader = reader;
1305                 this.headerAttributes = XmlAttributeHolder.emptyArray;
1306                 this.headers = new MessageHeaders(desiredVersion);
1307             }
1308             else
1309             {
1310                 envelopeAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders);
1311                 envelopePrefix = reader.Prefix;
1312                 EnvelopeVersion envelopeVersion = ReadStartEnvelope(reader);
1313                 if (desiredVersion.Envelope != envelopeVersion)
1314                 {
1315                     Exception versionMismatchException = new ArgumentException(SR.GetString(SR.EncoderEnvelopeVersionMismatch, envelopeVersion, desiredVersion.Envelope), "reader");
1316                     throw TraceUtility.ThrowHelperError(
1317                         new CommunicationException(versionMismatchException.Message, versionMismatchException),
1318                         this);
1319                 }
1320
1321                 if (HasHeaderElement(reader, envelopeVersion))
1322                 {
1323                     headerPrefix = reader.Prefix;
1324                     headerAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders);
1325                     headers = new MessageHeaders(desiredVersion, reader, envelopeAttributes, headerAttributes, ref maxSizeOfHeaders);
1326                 }
1327                 else
1328                 {
1329                     headerAttributes = XmlAttributeHolder.emptyArray;
1330                     headers = new MessageHeaders(desiredVersion);
1331                 }
1332
1333                 if (reader.NodeType != XmlNodeType.Element)
1334                     reader.MoveToContent();
1335                 bodyPrefix = reader.Prefix;
1336                 VerifyStartBody(reader, envelopeVersion);
1337                 bodyAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfHeaders);
1338                 if (ReadStartBody(reader))
1339                 {
1340                     this.reader = reader;
1341                 }
1342                 else
1343                 {
1344                     this.quotas = new XmlDictionaryReaderQuotas();
1345                     reader.Quotas.CopyTo(this.quotas);
1346                     reader.Close();
1347                 }
1348             }
1349         }
1350
1351         public override MessageHeaders Headers
1352         {
1353             get
1354             {
1355                 if (IsDisposed)
1356 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1357                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1358                 return headers;
1359             }
1360         }
1361
1362         public override MessageVersion Version
1363         {
1364             get
1365             {
1366                 return headers.MessageVersion;
1367             }
1368         }
1369
1370         public override MessageProperties Properties
1371         {
1372             get
1373             {
1374                 return properties;
1375             }
1376         }
1377
1378         protected override void OnBodyToString(XmlDictionaryWriter writer)
1379         {
1380             writer.WriteString(SR.GetString(SR.MessageBodyIsStream));
1381         }
1382
1383         protected override void OnClose()
1384         {
1385             Exception ex = null;
1386             try
1387             {
1388                 base.OnClose();
1389             }
1390             catch (Exception e)
1391             {
1392                 if (Fx.IsFatal(e))
1393                     throw;
1394                 ex = e;
1395             }
1396
1397             try
1398             {
1399                 properties.Dispose();
1400             }
1401             catch (Exception e)
1402             {
1403                 if (Fx.IsFatal(e))
1404                     throw;
1405                 if (ex == null)
1406                     ex = e;
1407             }
1408
1409             try
1410             {
1411                 if (reader != null)
1412                 {
1413                     reader.Close();
1414                 }
1415             }
1416             catch (Exception e)
1417             {
1418                 if (Fx.IsFatal(e))
1419                     throw;
1420                 if (ex == null)
1421                     ex = e;
1422             }
1423
1424             if (ex != null)
1425                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex);
1426         }
1427
1428         protected override XmlDictionaryReader OnGetReaderAtBodyContents()
1429         {
1430             XmlDictionaryReader reader = this.reader;
1431             this.reader = null;
1432             return reader;
1433         }
1434
1435         protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
1436         {
1437             if (this.reader != null)
1438                 return OnCreateBufferedCopy(maxBufferSize, this.reader.Quotas);
1439             return OnCreateBufferedCopy(maxBufferSize, this.quotas);
1440         }
1441
1442         protected override void OnWriteStartBody(XmlDictionaryWriter writer)
1443         {
1444             writer.WriteStartElement(bodyPrefix, MessageStrings.Body, Version.Envelope.Namespace);
1445             XmlAttributeHolder.WriteAttributes(bodyAttributes, writer);
1446         }
1447
1448         protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
1449         {
1450             EnvelopeVersion envelopeVersion = Version.Envelope;
1451             writer.WriteStartElement(envelopePrefix, MessageStrings.Envelope, envelopeVersion.Namespace);
1452             XmlAttributeHolder.WriteAttributes(envelopeAttributes, writer);
1453         }
1454
1455         protected override void OnWriteStartHeaders(XmlDictionaryWriter writer)
1456         {
1457             EnvelopeVersion envelopeVersion = Version.Envelope;
1458             writer.WriteStartElement(headerPrefix, MessageStrings.Header, envelopeVersion.Namespace);
1459             XmlAttributeHolder.WriteAttributes(headerAttributes, writer);
1460         }
1461
1462         protected override string OnGetBodyAttribute(string localName, string ns)
1463         {
1464             return XmlAttributeHolder.GetAttribute(bodyAttributes, localName, ns);
1465         }
1466     }
1467
1468     interface IBufferedMessageData
1469     {
1470         MessageEncoder MessageEncoder { get; }
1471         ArraySegment<byte> Buffer { get; }
1472         XmlDictionaryReaderQuotas Quotas { get; }
1473         void Close();
1474         void EnableMultipleUsers();
1475         XmlDictionaryReader GetMessageReader();
1476         void Open();
1477         void ReturnMessageState(RecycledMessageState messageState);
1478         RecycledMessageState TakeMessageState();
1479     }
1480
1481     sealed class BufferedMessage : ReceivedMessage
1482     {
1483         MessageHeaders headers;
1484         MessageProperties properties;
1485         IBufferedMessageData messageData;
1486         RecycledMessageState recycledMessageState;
1487         XmlDictionaryReader reader;
1488         XmlAttributeHolder[] bodyAttributes;
1489
1490         public BufferedMessage(IBufferedMessageData messageData, RecycledMessageState recycledMessageState)
1491             : this(messageData, recycledMessageState, null, false)
1492         {
1493         }
1494
1495         public BufferedMessage(IBufferedMessageData messageData, RecycledMessageState recycledMessageState, bool[] understoodHeaders, bool understoodHeadersModified)
1496         {
1497             bool throwing = true;
1498             try
1499             {
1500                 this.recycledMessageState = recycledMessageState;
1501                 this.messageData = messageData;
1502                 properties = recycledMessageState.TakeProperties();
1503                 if (properties == null)
1504                     this.properties = new MessageProperties();
1505                 XmlDictionaryReader reader = messageData.GetMessageReader();
1506                 MessageVersion desiredVersion = messageData.MessageEncoder.MessageVersion;
1507
1508                 if (desiredVersion.Envelope == EnvelopeVersion.None)
1509                 {
1510                     this.reader = reader;
1511                     this.headers = new MessageHeaders(desiredVersion);
1512                 }
1513                 else
1514                 {
1515                     EnvelopeVersion envelopeVersion = ReadStartEnvelope(reader);
1516                     if (desiredVersion.Envelope != envelopeVersion)
1517                     {
1518                         Exception versionMismatchException = new ArgumentException(SR.GetString(SR.EncoderEnvelopeVersionMismatch, envelopeVersion, desiredVersion.Envelope), "reader");
1519                         throw TraceUtility.ThrowHelperError(
1520                             new CommunicationException(versionMismatchException.Message, versionMismatchException),
1521                             this);
1522                     }
1523
1524                     if (HasHeaderElement(reader, envelopeVersion))
1525                     {
1526                         headers = recycledMessageState.TakeHeaders();
1527                         if (headers == null)
1528                         {
1529                             headers = new MessageHeaders(desiredVersion, reader, messageData, recycledMessageState, understoodHeaders, understoodHeadersModified);
1530                         }
1531                         else
1532                         {
1533                             headers.Init(desiredVersion, reader, messageData, recycledMessageState, understoodHeaders, understoodHeadersModified);
1534                         }
1535                     }
1536                     else
1537                     {
1538                         headers = new MessageHeaders(desiredVersion);
1539                     }
1540
1541                     VerifyStartBody(reader, envelopeVersion);
1542
1543                     int maxSizeOfAttributes = int.MaxValue;
1544                     bodyAttributes = XmlAttributeHolder.ReadAttributes(reader, ref maxSizeOfAttributes);
1545                     if (maxSizeOfAttributes < int.MaxValue - 4096)
1546                         bodyAttributes = null;
1547                     if (ReadStartBody(reader))
1548                     {
1549                         this.reader = reader;
1550                     }
1551                     else
1552                     {
1553                         reader.Close();
1554                     }
1555                 }
1556                 throwing = false;
1557             }
1558             finally
1559             {
1560                 if (throwing && MessageLogger.LoggingEnabled)
1561                 {
1562                     MessageLogger.LogMessage(messageData.Buffer, MessageLoggingSource.Malformed);
1563                 }
1564             }
1565         }
1566
1567         public override MessageHeaders Headers
1568         {
1569             get
1570             {
1571                 if (IsDisposed)
1572 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1573                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1574                 return headers;
1575             }
1576         }
1577
1578         internal IBufferedMessageData MessageData
1579         {
1580             get
1581             {
1582                 return messageData;
1583             }
1584         }
1585
1586         public override MessageProperties Properties
1587         {
1588             get
1589             {
1590                 if (IsDisposed)
1591 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose
1592                     throw TraceUtility.ThrowHelperError(CreateMessageDisposedException(), this);
1593                 return properties;
1594             }
1595         }
1596
1597         internal override RecycledMessageState RecycledMessageState
1598         {
1599             get { return recycledMessageState; }
1600         }
1601
1602         public override MessageVersion Version
1603         {
1604             get
1605             {
1606                 return headers.MessageVersion;
1607             }
1608         }
1609
1610         protected override XmlDictionaryReader OnGetReaderAtBodyContents()
1611         {
1612             XmlDictionaryReader reader = this.reader;
1613             this.reader = null;
1614             return reader;
1615         }
1616
1617         internal override XmlDictionaryReader GetReaderAtHeader()
1618         {
1619             if (!headers.ContainsOnlyBufferedMessageHeaders)
1620                 return base.GetReaderAtHeader();
1621             XmlDictionaryReader reader = messageData.GetMessageReader();
1622             if (reader.NodeType != XmlNodeType.Element)
1623                 reader.MoveToContent();
1624             reader.Read();
1625             if (HasHeaderElement(reader, headers.MessageVersion.Envelope))
1626                 return reader;
1627             return base.GetReaderAtHeader();
1628         }
1629
1630         public XmlDictionaryReader GetBufferedReaderAtBody()
1631         {
1632             XmlDictionaryReader reader = messageData.GetMessageReader();
1633             if (reader.NodeType != XmlNodeType.Element)
1634                 reader.MoveToContent();
1635             if (this.Version.Envelope != EnvelopeVersion.None)
1636             {
1637                 reader.Read();
1638                 if (HasHeaderElement(reader, headers.MessageVersion.Envelope))
1639                     reader.Skip();
1640                 if (reader.NodeType != XmlNodeType.Element)
1641                     reader.MoveToContent();
1642             }
1643             return reader;
1644         }
1645
1646         public XmlDictionaryReader GetMessageReader()
1647         {
1648             return messageData.GetMessageReader();
1649         }
1650
1651         protected override void OnBodyToString(XmlDictionaryWriter writer)
1652         {
1653             using (XmlDictionaryReader reader = GetBufferedReaderAtBody())
1654             {
1655                 if (this.Version == MessageVersion.None)
1656                 {
1657                     writer.WriteNode(reader, false);
1658                 }
1659                 else
1660                 {
1661                     if (!reader.IsEmptyElement)
1662                     {
1663                         reader.ReadStartElement();
1664                         while (reader.NodeType != XmlNodeType.EndElement)
1665                             writer.WriteNode(reader, false);
1666                     }
1667                 }
1668             }
1669         }
1670
1671         protected override void OnClose()
1672         {
1673             Exception ex = null;
1674             try
1675             {
1676                 base.OnClose();
1677             }
1678             catch (Exception e)
1679             {
1680                 if (Fx.IsFatal(e))
1681                     throw;
1682                 ex = e;
1683             }
1684
1685             try
1686             {
1687                 properties.Dispose();
1688             }
1689             catch (Exception e)
1690             {
1691                 if (Fx.IsFatal(e))
1692                     throw;
1693                 if (ex == null)
1694                     ex = e;
1695             }
1696
1697             try
1698             {
1699                 if (reader != null)
1700                 {
1701                     reader.Close();
1702                 }
1703             }
1704             catch (Exception e)
1705             {
1706                 if (Fx.IsFatal(e))
1707                     throw;
1708                 if (ex == null)
1709                     ex = e;
1710             }
1711
1712             try
1713             {
1714                 recycledMessageState.ReturnHeaders(headers);
1715                 recycledMessageState.ReturnProperties(properties);
1716                 messageData.ReturnMessageState(recycledMessageState);
1717                 recycledMessageState = null;
1718                 messageData.Close();
1719                 messageData = null;
1720             }
1721             catch (Exception e)
1722             {
1723                 if (Fx.IsFatal(e))
1724                     throw;
1725                 if (ex == null)
1726                     ex = e;
1727             }
1728
1729             if (ex != null)
1730                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ex);
1731         }
1732
1733         protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
1734         {
1735             using (XmlDictionaryReader reader = GetMessageReader())
1736             {
1737                 reader.MoveToContent();
1738                 EnvelopeVersion envelopeVersion = Version.Envelope;
1739                 writer.WriteStartElement(reader.Prefix, MessageStrings.Envelope, envelopeVersion.Namespace);
1740                 writer.WriteAttributes(reader, false);
1741             }
1742         }
1743
1744         protected override void OnWriteStartHeaders(XmlDictionaryWriter writer)
1745         {
1746             using (XmlDictionaryReader reader = GetMessageReader())
1747             {
1748                 reader.MoveToContent();
1749                 EnvelopeVersion envelopeVersion = Version.Envelope;
1750                 reader.Read();
1751                 if (HasHeaderElement(reader, envelopeVersion))
1752                 {
1753                     writer.WriteStartElement(reader.Prefix, MessageStrings.Header, envelopeVersion.Namespace);
1754                     writer.WriteAttributes(reader, false);
1755                 }
1756                 else
1757                 {
1758                     writer.WriteStartElement(MessageStrings.Prefix, MessageStrings.Header, envelopeVersion.Namespace);
1759                 }
1760             }
1761         }
1762
1763         protected override void OnWriteStartBody(XmlDictionaryWriter writer)
1764         {
1765             using (XmlDictionaryReader reader = GetBufferedReaderAtBody())
1766             {
1767                 writer.WriteStartElement(reader.Prefix, MessageStrings.Body, Version.Envelope.Namespace);
1768                 writer.WriteAttributes(reader, false);
1769             }
1770         }
1771
1772         protected override MessageBuffer OnCreateBufferedCopy(int maxBufferSize)
1773         {
1774             if (headers.ContainsOnlyBufferedMessageHeaders)
1775             {
1776                 KeyValuePair<string, object>[] properties = new KeyValuePair<string, object>[Properties.Count];
1777                 ((ICollection<KeyValuePair<string, object>>)Properties).CopyTo(properties, 0);
1778                 messageData.EnableMultipleUsers();
1779                 bool[] understoodHeaders = null;
1780                 if (headers.HasMustUnderstandBeenModified)
1781                 {
1782                     understoodHeaders = new bool[headers.Count];
1783                     for (int i = 0; i < headers.Count; i++)
1784                     {
1785                         understoodHeaders[i] = headers.IsUnderstood(i);
1786                     }
1787                 }
1788                 return new BufferedMessageBuffer(messageData, properties, understoodHeaders, headers.HasMustUnderstandBeenModified);
1789             }
1790             else
1791             {
1792                 if (this.reader != null)
1793                     return OnCreateBufferedCopy(maxBufferSize, this.reader.Quotas);
1794                 return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max);
1795             }
1796         }
1797
1798         protected override string OnGetBodyAttribute(string localName, string ns)
1799         {
1800             if (this.bodyAttributes != null)
1801                 return XmlAttributeHolder.GetAttribute(this.bodyAttributes, localName, ns);
1802             using (XmlDictionaryReader reader = GetBufferedReaderAtBody())
1803             {
1804                 return reader.GetAttribute(localName, ns);
1805             }
1806         }
1807     }
1808
1809     struct XmlAttributeHolder
1810     {
1811         string prefix;
1812         string ns;
1813         string localName;
1814         string value;
1815
1816         public static XmlAttributeHolder[] emptyArray = new XmlAttributeHolder[0];
1817
1818         public XmlAttributeHolder(string prefix, string localName, string ns, string value)
1819         {
1820             this.prefix = prefix;
1821             this.localName = localName;
1822             this.ns = ns;
1823             this.value = value;
1824         }
1825
1826         public string Prefix
1827         {
1828             get { return prefix; }
1829         }
1830
1831         public string NamespaceUri
1832         {
1833             get { return ns; }
1834         }
1835
1836         public string LocalName
1837         {
1838             get { return localName; }
1839         }
1840
1841         public string Value
1842         {
1843             get { return value; }
1844         }
1845
1846         public void WriteTo(XmlWriter writer)
1847         {
1848             writer.WriteStartAttribute(prefix, localName, ns);
1849             writer.WriteString(value);
1850             writer.WriteEndAttribute();
1851         }
1852
1853         public static void WriteAttributes(XmlAttributeHolder[] attributes, XmlWriter writer)
1854         {
1855             for (int i = 0; i < attributes.Length; i++)
1856                 attributes[i].WriteTo(writer);
1857         }
1858
1859         public static XmlAttributeHolder[] ReadAttributes(XmlDictionaryReader reader)
1860         {
1861             int maxSizeOfHeaders = int.MaxValue;
1862             return ReadAttributes(reader, ref maxSizeOfHeaders);
1863         }
1864
1865         public static XmlAttributeHolder[] ReadAttributes(XmlDictionaryReader reader, ref int maxSizeOfHeaders)
1866         {
1867             if (reader.AttributeCount == 0)
1868                 return emptyArray;
1869             XmlAttributeHolder[] attributes = new XmlAttributeHolder[reader.AttributeCount];
1870             reader.MoveToFirstAttribute();
1871             for (int i = 0; i < attributes.Length; i++)
1872             {
1873                 string ns = reader.NamespaceURI;
1874                 string localName = reader.LocalName;
1875                 string prefix = reader.Prefix;
1876                 string value = string.Empty;
1877                 while (reader.ReadAttributeValue())
1878                 {
1879                     if (value.Length == 0)
1880                         value = reader.Value;
1881                     else
1882                         value += reader.Value;
1883                 }
1884                 Deduct(prefix, ref maxSizeOfHeaders);
1885                 Deduct(localName, ref maxSizeOfHeaders);
1886                 Deduct(ns, ref maxSizeOfHeaders);
1887                 Deduct(value, ref maxSizeOfHeaders);
1888                 attributes[i] = new XmlAttributeHolder(prefix, localName, ns, value);
1889                 reader.MoveToNextAttribute();
1890             }
1891             reader.MoveToElement();
1892             return attributes;
1893         }
1894
1895         static void Deduct(string s, ref int maxSizeOfHeaders)
1896         {
1897             int byteCount = s.Length * sizeof(char);
1898             if (byteCount > maxSizeOfHeaders)
1899             {
1900                 string message = SR.GetString(SR.XmlBufferQuotaExceeded);
1901                 Exception inner = new QuotaExceededException(message);
1902                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message, inner));
1903             }
1904             maxSizeOfHeaders -= byteCount;
1905         }
1906
1907         public static string GetAttribute(XmlAttributeHolder[] attributes, string localName, string ns)
1908         {
1909             for (int i = 0; i < attributes.Length; i++)
1910                 if (attributes[i].LocalName == localName && attributes[i].NamespaceUri == ns)
1911                     return attributes[i].Value;
1912             return null;
1913         }
1914     }
1915
1916     class RecycledMessageState
1917     {
1918         MessageHeaders recycledHeaders;
1919         MessageProperties recycledProperties;
1920         UriCache uriCache;
1921         HeaderInfoCache headerInfoCache;
1922
1923         public HeaderInfoCache HeaderInfoCache
1924         {
1925             get
1926             {
1927                 if (headerInfoCache == null)
1928                 {
1929                     headerInfoCache = new HeaderInfoCache();
1930                 }
1931                 return headerInfoCache;
1932             }
1933         }
1934
1935         public UriCache UriCache
1936         {
1937             get
1938             {
1939                 if (uriCache == null)
1940                     uriCache = new UriCache();
1941                 return uriCache;
1942             }
1943         }
1944
1945         public MessageProperties TakeProperties()
1946         {
1947             MessageProperties taken = recycledProperties;
1948             recycledProperties = null;
1949             return taken;
1950         }
1951
1952         public void ReturnProperties(MessageProperties properties)
1953         {
1954             if (properties.CanRecycle)
1955             {
1956                 properties.Recycle();
1957                 this.recycledProperties = properties;
1958             }
1959         }
1960
1961         public MessageHeaders TakeHeaders()
1962         {
1963             MessageHeaders taken = recycledHeaders;
1964             recycledHeaders = null;
1965             return taken;
1966         }
1967
1968         public void ReturnHeaders(MessageHeaders headers)
1969         {
1970             if (headers.CanRecycle)
1971             {
1972                 headers.Recycle(this.HeaderInfoCache);
1973                 this.recycledHeaders = headers;
1974             }
1975         }
1976     }
1977
1978     class HeaderInfoCache
1979     {
1980         const int maxHeaderInfos = 4;
1981         HeaderInfo[] headerInfos;
1982         int index;
1983
1984         public MessageHeaderInfo TakeHeaderInfo(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isRefParam)
1985         {
1986             if (this.headerInfos != null)
1987             {
1988                 int i = this.index;
1989                 for (;;)
1990                 {
1991                     HeaderInfo headerInfo = this.headerInfos[i];
1992                     if (headerInfo != null)
1993                     {
1994                         if (headerInfo.Matches(reader, actor, mustUnderstand, relay, isRefParam))
1995                         {
1996                             this.headerInfos[i] = null;
1997                             this.index = (i + 1) % maxHeaderInfos;
1998                             return headerInfo;
1999                         }
2000                     }
2001                     i = (i + 1) % maxHeaderInfos;
2002                     if (i == this.index)
2003                     {
2004                         break;
2005                     }
2006                 }
2007             }
2008
2009             return new HeaderInfo(reader, actor, mustUnderstand, relay, isRefParam);
2010         }
2011
2012         public void ReturnHeaderInfo(MessageHeaderInfo headerInfo)
2013         {
2014             HeaderInfo headerInfoToReturn = headerInfo as HeaderInfo;
2015             if (headerInfoToReturn != null)
2016             {
2017                 if (this.headerInfos == null)
2018                 {
2019                     this.headerInfos = new HeaderInfo[maxHeaderInfos];
2020                 }
2021                 int i = this.index;
2022                 for (;;)
2023                 {
2024                     if (this.headerInfos[i] == null)
2025                     {
2026                         break;
2027                     }
2028                     i = (i + 1) % maxHeaderInfos;
2029                     if (i == this.index)
2030                     {
2031                         break;
2032                     }
2033                 }
2034                 this.headerInfos[i] = headerInfoToReturn;
2035                 this.index = (i + 1) % maxHeaderInfos;
2036             }
2037         }
2038
2039         class HeaderInfo : MessageHeaderInfo
2040         {
2041             string name;
2042             string ns;
2043             string actor;
2044             bool isReferenceParameter;
2045             bool mustUnderstand;
2046             bool relay;
2047
2048             public HeaderInfo(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isReferenceParameter)
2049             {
2050                 this.actor = actor;
2051                 this.mustUnderstand = mustUnderstand;
2052                 this.relay = relay;
2053                 this.isReferenceParameter = isReferenceParameter;
2054                 reader.GetNonAtomizedNames(out name, out ns);
2055             }
2056
2057             public override string Name
2058             {
2059                 get { return name; }
2060             }
2061
2062             public override string Namespace
2063             {
2064                 get { return ns; }
2065             }
2066
2067             public override bool IsReferenceParameter
2068             {
2069                 get { return isReferenceParameter; }
2070             }
2071
2072             public override string Actor
2073             {
2074                 get { return actor; }
2075             }
2076
2077             public override bool MustUnderstand
2078             {
2079                 get { return mustUnderstand; }
2080             }
2081
2082             public override bool Relay
2083             {
2084                 get { return relay; }
2085             }
2086
2087             public bool Matches(XmlDictionaryReader reader, string actor, bool mustUnderstand, bool relay, bool isRefParam)
2088             {
2089                 return reader.IsStartElement(this.name, this.ns) &&
2090                     this.actor == actor && this.mustUnderstand == mustUnderstand && this.relay == relay && this.isReferenceParameter == isRefParam;
2091             }
2092         }
2093     }
2094
2095     class UriCache
2096     {
2097         const int MaxKeyLength = 128;
2098         const int MaxEntries = 8;
2099         Entry[] entries;
2100         int count;
2101
2102         public UriCache()
2103         {
2104             entries = new Entry[MaxEntries];
2105         }
2106
2107         public Uri CreateUri(string uriString)
2108         {
2109             Uri uri = Get(uriString);
2110             if (uri == null)
2111             {
2112                 uri = new Uri(uriString);
2113                 Set(uriString, uri);
2114             }
2115             return uri;
2116         }
2117
2118         Uri Get(string key)
2119         {
2120             if (key.Length > MaxKeyLength)
2121                 return null;
2122             for (int i = count - 1; i >= 0; i--)
2123                 if (entries[i].Key == key)
2124                     return entries[i].Value;
2125             return null;
2126         }
2127
2128         void Set(string key, Uri value)
2129         {
2130             if (key.Length > MaxKeyLength)
2131                 return;
2132             if (count < entries.Length)
2133             {
2134                 entries[count++] = new Entry(key, value);
2135             }
2136             else
2137             {
2138                 Array.Copy(entries, 1, entries, 0, entries.Length - 1);
2139                 entries[count - 1] = new Entry(key, value);
2140             }
2141         }
2142
2143         struct Entry
2144         {
2145             string key;
2146             Uri value;
2147
2148             public Entry(string key, Uri value)
2149             {
2150                 this.key = key;
2151                 this.value = value;
2152             }
2153
2154             public string Key
2155             {
2156                 get { return key; }
2157             }
2158
2159             public Uri Value
2160             {
2161                 get { return value; }
2162             }
2163         }
2164     }
2165 }