5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2006 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Collections.Generic;
31 using System.Runtime.Serialization;
35 namespace System.ServiceModel.Channels
37 internal class AttributeInfo
39 public string Prefix, Name, Namespace, Value;
42 internal class AttributeCollection : List<AttributeInfo>
44 public AttributeCollection ()
48 public AttributeCollection (AttributeCollection copy)
54 internal class XmlReaderMessage : Message
56 MessageVersion version;
57 XmlDictionaryReader reader;
58 MessageHeaders headers;
59 MessageProperties properties = new MessageProperties ();
60 bool is_empty, is_fault, body_started, body_consumed;
62 AttributeCollection attributes;
64 public XmlReaderMessage (MessageVersion version, XmlDictionaryReader reader, int maxSizeOfHeaders)
66 this.version = version;
68 this.max_headers = maxSizeOfHeaders;
73 public override MessageHeaders Headers {
81 public override bool IsEmpty {
88 public override bool IsFault {
95 public override MessageProperties Properties {
96 get { return properties; }
99 public override MessageVersion Version {
100 get { return version; }
103 protected override MessageBuffer OnCreateBufferedCopy (
107 var headers = new MessageHeaders (Headers);
108 var props = new MessageProperties (Properties);
110 return new DefaultMessageBuffer (headers, props, attributes);
112 return new DefaultMessageBuffer (maxBufferSize, headers, props, new XmlReaderBodyWriter (reader), IsFault, attributes);
115 protected override string OnGetBodyAttribute (
116 string localName, string ns)
119 var att = attributes.FirstOrDefault (a => a.Name == localName && a.Namespace == ns);
120 return att != null ? att.Value : null;
123 protected override XmlDictionaryReader OnGetReaderAtBodyContents ()
125 if (reader.ReadState == ReadState.Closed)
126 return reader; // silly, but that's what our test expects.
129 throw new InvalidOperationException ("The message body is empty.");
130 body_consumed = true;
134 protected override void OnWriteBodyContents (
135 XmlDictionaryWriter writer)
137 XmlDictionaryReader reader = GetReaderAtBodyContents ();
138 while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement)
139 writer.WriteNode (reader, false);
142 static readonly char [] whitespaceChars = new char [] {' ', '\t', '\r', '\n'};
144 void ReadEnvelopeStart ()
146 reader.MoveToContent ();
147 if (reader.IsEmptyElement)
148 throw new ArgumentException ("Missing message content XML.");
149 reader.ReadStartElement ("Envelope", Version.Envelope.Namespace);
152 reader.MoveToContent ();
158 throw new InvalidOperationException ("XmlReader at headers is already consumed.");
160 string envNS = Version.Envelope.Namespace;
162 headers = new MessageHeaders (version);
163 if (reader.LocalName != "Header" || reader.NamespaceURI != envNS)
166 bool isEmptyHeader = reader.IsEmptyElement;
167 reader.ReadStartElement ("Header", envNS);
168 reader.MoveToContent ();
173 while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement) {
174 if (reader.NodeType == XmlNodeType.Element) {
175 if (nHeaders++ == max_headers)
176 throw new InvalidOperationException (String.Format ("Message header size has exceeded the maximum header size {0}", max_headers));
177 headers.Add (new MessageHeader.XmlMessageHeader (reader, Version));
181 // FIXME: handle UnderstoodHeaders as well.
182 reader.MoveToContent ();
184 reader.ReadEndElement ();
185 reader.MoveToContent ();
188 void ReadBodyStart ()
191 throw new InvalidOperationException ("The message body XmlReader is already consumed.");
196 // read headers in advance.
202 is_empty = reader.IsEmptyElement;
203 attributes = new AttributeCollection ();
204 reader.MoveToContent ();
205 if (reader.MoveToFirstAttribute ()) {
207 attributes.Add (new AttributeInfo () { Prefix = reader.Prefix, Name = reader.LocalName, Namespace = reader.NamespaceURI, Value = reader.Value});
208 } while (reader.MoveToNextAttribute ());
209 reader.MoveToElement ();
211 reader.ReadStartElement ("Body", Version.Envelope.Namespace);
212 if (reader.NodeType == XmlNodeType.EndElement) {
216 reader.MoveToContent ();
217 if (reader.NodeType == XmlNodeType.Element &&
218 reader.LocalName == "Fault" &&
219 reader.NamespaceURI == Version.Envelope.Namespace)
224 protected override void OnWriteStartBody (
225 XmlDictionaryWriter writer)
227 ReadBodyStart (); // consume up to attributes
229 base.OnWriteStartBody (writer);
230 foreach (var p in attributes)
231 writer.WriteAttributeString (p.Prefix, p.Name, p.Namespace, p.Value);
235 internal abstract class MessageImplBase : Message
237 MessageHeaders headers;
238 MessageProperties properties = new MessageProperties ();
239 AttributeCollection attributes;
241 public MessageImplBase (MessageVersion version, string action, AttributeCollection attributes)
243 headers = new MessageHeaders (version);
245 headers.Action = action;
246 this.attributes = attributes;
249 internal AttributeCollection Attributes {
250 get { return attributes; }
253 public override MessageHeaders Headers {
254 get { return headers; }
257 public override MessageProperties Properties {
258 get { return properties; }
261 public override MessageVersion Version {
262 get { return Headers.MessageVersion; }
265 protected override string OnGetBodyAttribute (
266 string localName, string ns)
268 var att = attributes.FirstOrDefault (a => a.Name == localName && a.Namespace == ns);
269 return att != null ? att.Value : null;
272 protected override void OnWriteStartBody (
273 XmlDictionaryWriter writer)
275 var dic = Constants.SoapDictionary;
276 writer.WriteStartElement ("s", dic.Add ("Body"), dic.Add (Version.Envelope.Namespace));
277 foreach (var p in Attributes)
278 writer.WriteAttributeString (p.Prefix, p.Name, p.Namespace, p.Value);
282 internal class EmptyMessage : MessageImplBase
284 static readonly AttributeCollection empty_attributes = new AttributeCollection ();
286 public EmptyMessage (MessageVersion version, string action)
287 : base (version, action, empty_attributes)
291 public override bool IsEmpty {
295 protected override void OnWriteBodyContents (
296 XmlDictionaryWriter writer)
300 protected override MessageBuffer OnCreateBufferedCopy (
303 return new DefaultMessageBuffer (Headers, Properties, Attributes);
307 internal class SimpleMessage : MessageImplBase
312 public SimpleMessage (MessageVersion version,
313 string action, BodyWriter body, bool isFault, AttributeCollection attributes)
314 : base (version, action, attributes)
317 this.is_fault = isFault;
320 public override bool IsEmpty {
321 get { return false; }
324 public override bool IsFault {
325 get { return is_fault; }
328 protected override void OnWriteBodyContents (
329 XmlDictionaryWriter writer)
331 body.WriteBodyContents (writer);
334 protected override MessageBuffer OnCreateBufferedCopy (
337 var headers = new MessageHeaders (Headers);
338 var props = new MessageProperties (Properties);
339 var atts = new AttributeCollection (Attributes);
340 return new DefaultMessageBuffer (maxBufferSize, headers, props, body.CreateBufferedCopy (maxBufferSize), IsFault, atts);