move to from olive to mcs
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Channels / MessageImpl.cs
1 //
2 // MessageImpl.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2006 Novell, Inc.  http://www.novell.com
8 //
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
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.
27 //
28 using System;
29 using System.Runtime.Serialization;
30 using System.Xml;
31 using System.IO;
32
33 namespace System.ServiceModel.Channels
34 {
35         // Apparently Microsoft should have split Message class into
36         // two diffferent public classes such as IncomingMessage and
37         // OutgoingMessage.
38         internal class XmlReaderMessage : Message
39         {
40                 MessageVersion version;
41                 XmlDictionaryReader reader;
42                 MessageHeaders headers;
43                 MessageProperties properties = new MessageProperties ();
44                 bool is_empty, is_fault, body_started, body_consumed;
45                 int max_headers;
46
47                 string body;
48
49                 public XmlReaderMessage (MessageVersion version, XmlDictionaryReader reader, int maxSizeOfHeaders)
50                 {
51                         this.version = version;
52                         this.reader = reader;
53                         this.max_headers = maxSizeOfHeaders;
54
55                         ReadEnvelopeStart ();
56                         // Headers and IsEmpty are consumed at this stage.
57                         // Body content is not.
58                         ReadBodyStart ();
59
60                         StringWriter sw = new StringWriter ();
61                         using (XmlDictionaryWriter bodyXml = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw))) {
62                                 while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement)
63                                         bodyXml.WriteNode (reader, false);
64                         }
65                         this.body = sw.ToString ();
66                 }
67
68                 public override MessageHeaders Headers {
69                         get {
70                                 if (headers == null)
71                                         ReadHeaders ();
72                                 return headers;
73                         }
74                 }
75
76                 public override bool IsEmpty {
77                         get {
78                                 if (!body_started)
79                                         ReadBodyStart ();
80                                 return is_empty;
81                         }
82                 }
83
84                 public override bool IsFault {
85                         get {
86                                 if (!body_started)
87                                         ReadBodyStart ();
88                                 return is_fault;
89                         }
90                 }
91
92                 public override MessageProperties Properties {
93                         get { return properties; }
94                 }
95
96                 public override MessageVersion Version {
97                         get { return version; }
98                 }
99
100                 protected override string OnGetBodyAttribute (
101                         string localName, string ns)
102                 {
103                         if (headers == null)
104                                 ReadHeaders ();
105                         return reader.GetAttribute (localName, ns);
106                 }
107
108                 protected override XmlDictionaryReader OnGetReaderAtBodyContents ()
109                 {
110                         XmlDictionaryReader newReader = XmlDictionaryReader.CreateDictionaryReader (XmlReader.Create (new StringReader (this.body)));
111                         newReader.MoveToContent();
112                         return newReader;
113                 }
114
115                 protected override void OnWriteBodyContents (
116                         XmlDictionaryWriter writer)
117                 {
118                         XmlDictionaryReader reader = GetReaderAtBodyContents ();
119                         while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement)
120                                 writer.WriteNode (reader, false);
121                 }
122
123                 static readonly char [] whitespaceChars = new char [] {' ', '\t', '\r', '\n'};
124
125                 void ReadEnvelopeStart ()
126                 {
127                         reader.MoveToContent ();
128                         if (reader.IsEmptyElement)
129                                 throw new ArgumentException ("Missing message content XML.");
130                         reader.ReadStartElement ("Envelope", Version.Envelope.Namespace);
131
132                         // SOAP Header
133                         reader.MoveToContent ();
134                 }
135
136                 void ReadHeaders ()
137                 {
138                         if (headers != null)
139                                 throw new InvalidOperationException ("XmlReader at headers is already consumed.");
140
141                         string envNS = Version.Envelope.Namespace;
142
143                         headers = new MessageHeaders (version, max_headers);
144                         if (reader.LocalName != "Header" || reader.NamespaceURI != envNS)
145                                 return;
146
147                         bool isEmptyHeader = reader.IsEmptyElement;
148                         reader.ReadStartElement ("Header", envNS);
149                         reader.MoveToContent ();
150                         if (isEmptyHeader)
151                                 return;
152
153                         XmlDocument doc = null;
154                         while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement) {
155                                 if (doc == null)
156                                         doc = new XmlDocument ();
157                                 XmlElement el = doc.ReadNode (reader) as XmlElement;
158                                 if (el != null)
159                                         headers.Add (MessageHeader.CreateInternalHeader (el, envNS));
160                                 // FIXME: handle UnderstoodHeaders as well.
161                                 reader.MoveToContent ();
162                         }
163                         reader.ReadEndElement ();
164                         reader.MoveToContent ();
165                 }
166
167                 void ReadBodyStart ()
168                 {
169                         // read headers in advance.
170                         if (headers == null)
171                                 ReadHeaders ();
172
173                         // SOAP Body
174                         body_started = true;
175                         is_empty = reader.IsEmptyElement;
176                         if (reader.MoveToAttribute ("Id", Constants.WsuNamespace)) {
177                                 BodyId = reader.Value;
178                                 reader.MoveToElement ();
179                         }
180                         reader.ReadStartElement ("Body", Version.Envelope.Namespace);
181                         if (reader.NodeType == XmlNodeType.EndElement) {
182                                 is_empty = true;
183                                 reader.Read ();
184                         } else {
185                                 reader.MoveToContent ();
186                                 if (reader.NodeType == XmlNodeType.Element &&
187                                     reader.LocalName == "Fault" &&
188                                     reader.NamespaceURI == Version.Envelope.Namespace)
189                                         is_fault = true;
190                         }
191                 }
192         }
193
194         internal abstract class MessageImplBase : Message
195         {
196                 MessageHeaders headers;
197                 MessageProperties properties = new MessageProperties ();
198
199                 public MessageImplBase (MessageVersion version, string action)
200                 {
201                         headers = new MessageHeaders (version);
202                         if (action != null)
203                                 headers.Action = action;
204                 }
205
206                 public override MessageHeaders Headers {
207                         get { return headers; }
208                 }
209
210                 public override MessageProperties Properties {
211                         get { return properties; }
212                 }
213
214                 public override MessageVersion Version {
215                         get { return Headers.MessageVersion; }
216                 }
217         }
218
219         internal class EmptyMessage : MessageImplBase
220         {
221                 public EmptyMessage (MessageVersion version, string action)
222                         : base (version, action)
223                 {
224                 }
225
226                 public override bool IsEmpty {
227                         get { return true; }
228                 }
229
230                 protected override void OnWriteBodyContents (
231                         XmlDictionaryWriter writer)
232                 {
233                 }
234
235                 protected override MessageBuffer OnCreateBufferedCopy (
236                         int maxBufferSize)
237                 {
238                         return new DefaultMessageBuffer (Headers, Properties);
239                 }
240         }
241
242         internal class SimpleMessage : MessageImplBase
243         {
244                 BodyWriter body;
245                 bool is_fault;
246
247                 public SimpleMessage (MessageVersion version,
248                         string action, BodyWriter body, bool isFault)
249                         : base (version, action)
250                 {
251                         this.body = body;
252                         this.is_fault = isFault;
253                 }
254
255                 public override bool IsEmpty {
256                         get { return false; }
257                 }
258
259                 public override bool IsFault {
260                         get { return is_fault; }
261                 }
262
263                 protected override void OnWriteBodyContents (
264                         XmlDictionaryWriter writer)
265                 {
266                         body.WriteBodyContents (writer);
267                 }
268         }
269 }