Merge pull request #3528 from BrzVlad/fix-sgen-check-before-collections
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / EndpointAddress.cs
1 //
2 // System.ServiceModel.EndpointAddress.cs
3 //
4 // Author: Duncan Mak (duncan@novell.com)
5 //         Atsushi Enomoto (atsushi@ximian.com)
6 //
7 // Copyright (C) 2005-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
29 using System;
30 using System.IO;
31 using System.Reflection;
32 using System.Resources;
33 using System.Runtime.Serialization;
34 using System.Security.Cryptography.X509Certificates;
35 using System.Xml;
36 using System.Xml.Schema;
37 using System.Xml.Serialization;
38 using System.ServiceModel.Channels;
39 using System.ServiceModel.Description;
40 #if !MOBILE
41 using System.Security.Cryptography.Xml;
42 #endif
43
44 namespace System.ServiceModel
45 {
46         public class EndpointAddress
47         {
48                 static readonly Uri w3c_anonymous = new Uri (Constants.WsaAnonymousUri);
49                 static readonly Uri anonymous_role = new Uri ("http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous");
50                 static readonly Uri none_role = new Uri ("http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/None");
51
52                 public static Uri AnonymousUri {
53                         get { return anonymous_role; }
54                 }
55
56                 public static Uri NoneUri {
57                         get { return none_role; }
58                 }
59
60                 Uri address;
61                 AddressHeaderCollection headers;
62                 EndpointIdentity identity;
63                 XmlDictionaryReader metadata_reader;
64                 XmlDictionaryReader extension_reader;
65
66                 static XmlSchema schema;
67
68                 public EndpointAddress (string uri)
69                         : this (new Uri (uri), new AddressHeader [0])
70                 {
71                 }
72
73                 public EndpointAddress (Uri uri, params AddressHeader [] addressHeaders)
74                         : this (uri, null, new AddressHeaderCollection (addressHeaders), null, null) {}
75
76                 public EndpointAddress (Uri uri, EndpointIdentity identity, params AddressHeader [] addressHeaders)
77                         : this (uri, identity, new AddressHeaderCollection (addressHeaders), null, null) {}
78
79                 public EndpointAddress (Uri uri, EndpointIdentity identity, AddressHeaderCollection headers)
80                         : this (uri, identity, headers, null, null) {}
81
82                 public EndpointAddress (
83                         Uri uri, EndpointIdentity identity,
84                         AddressHeaderCollection headers,
85                         XmlDictionaryReader metadataReader,
86                         XmlDictionaryReader extensionReader)
87                 {       
88                         if (uri == null)
89                                 throw new ArgumentNullException ("uri");
90                         if (!uri.IsAbsoluteUri)
91                                 throw new ArgumentException ("The argument uri must be absolute");
92                         this.address = uri;
93                         this.identity = identity;
94                         this.headers = headers;
95                         metadata_reader = metadataReader;
96                         extension_reader = extensionReader;
97                 }
98
99                 public bool IsAnonymous {
100                         get { return address.Equals (anonymous_role); }
101                 }
102
103                 public bool IsNone {
104                         get { return address.Equals (none_role); }
105                 }
106
107                 public AddressHeaderCollection Headers {
108                         get { return headers; }
109                 }
110
111                 public EndpointIdentity Identity {
112                         get { return identity; }
113                 }
114
115                 public Uri Uri {
116                         get { return address; }
117                 }
118
119 #if !MOBILE
120                 internal static XmlSchema Schema {
121                         get {
122                                 if (schema == null) {
123                                         Assembly a = Assembly.GetCallingAssembly ();
124                                         Stream s = a.GetManifestResourceStream ("WS-Addressing.schema");
125                                         schema = XmlSchema.Read (s, null);
126                                 }
127
128                                 return schema;
129                         }
130                 }
131 #endif
132
133                 [MonoTODO]
134                 public void ApplyTo (Message message)
135                 {
136                         throw new NotImplementedException ();
137                 }
138
139                 public override bool Equals (object obj)
140                 {
141                         EndpointAddress other = obj as EndpointAddress;
142                         if (other == null || 
143                             other.Uri == null || !other.Uri.Equals (this.Uri) ||
144                             other.Headers.Count != this.Headers.Count)
145                                 return false;
146
147                         foreach (AddressHeader h in this.Headers) {
148                                 bool match = false;
149                                 foreach (AddressHeader o in other.Headers)
150                                         if (h.Equals (o)) {
151                                                 match = true;
152                                                 break;
153                                         }
154                                 if (!match)
155                                         return false;
156                         }
157
158                         return true;
159                 }
160
161                 public override int GetHashCode ()
162                 {
163                         return address.GetHashCode ();
164                 }
165
166                 public XmlDictionaryReader GetReaderAtExtensions ()
167                 {
168                         return extension_reader;
169                 }
170
171                 public XmlDictionaryReader GetReaderAtMetadata ()
172                 {
173                         return metadata_reader;
174                 }
175
176                 public static bool operator == (EndpointAddress address1, EndpointAddress address2)
177                 {
178                         if ((object) address1 == null)
179                                 return (object) address2 == null;
180                         if ((object) address2 == null)
181                                 return false;
182                         return address1.Equals (address2);
183                 }
184
185                 public static bool operator != (EndpointAddress address1, EndpointAddress address2)
186                 {
187                         return ! (address1 == address2);
188                 }
189
190 //#if !MOBILE
191                 public static EndpointAddress ReadFrom (
192                         XmlDictionaryReader reader)
193                 {
194                         if (reader == null)
195                                 throw new ArgumentNullException ("reader");
196
197                         return ReadFromInternal (null, reader, null, null, null, null);
198                 }
199
200                 public static EndpointAddress ReadFrom (
201                         AddressingVersion addressingVersion,
202                         XmlDictionaryReader reader)
203                 {
204                         return ReadFrom (addressingVersion, (XmlReader) reader);
205                 }
206
207                 public static EndpointAddress ReadFrom (
208                         AddressingVersion addressingVersion,
209                         XmlReader reader)
210                 {
211                         if (addressingVersion == null)
212                                 throw new ArgumentNullException ("addressingVersion");
213                         if (reader == null)
214                                 throw new ArgumentNullException ("reader");
215
216                         return ReadFromInternal (addressingVersion, reader, null, null, null, null);
217                 }
218
219                 public static EndpointAddress ReadFrom (
220                         XmlDictionaryReader reader,
221                         XmlDictionaryString localName,
222                         XmlDictionaryString ns)
223                 {
224                         return ReadFrom (AddressingVersion.WSAddressing10,
225                                          reader, localName, ns);
226                 }
227
228                 public static EndpointAddress ReadFrom (
229                         AddressingVersion addressingVersion,
230                         XmlDictionaryReader reader,
231                         XmlDictionaryString localName,
232                         XmlDictionaryString ns)
233                 {
234                         // Empty localName and ns will be rejected by ReadStartElement() by feeding empty strings.
235                         return ReadFromInternal (addressingVersion, reader, null, null, localName ?? XmlDictionaryString.Empty, ns ?? XmlDictionaryString.Empty);
236                 }
237
238                 public static EndpointAddress ReadFrom (
239                         AddressingVersion addressingVersion,
240                         XmlReader reader, string localName, string ns)
241                 {
242                         // Empty localName and ns will be rejected by ReadStartElement() by feeding empty strings.
243                         return ReadFromInternal (addressingVersion, reader, localName ?? String.Empty, ns ?? String.Empty, null, null);
244                 }
245
246                 private static EndpointAddress ReadFromInternal (
247                         AddressingVersion addressingVersion,
248                         XmlReader reader, string localName, string ns,
249                         XmlDictionaryString dictLocalName,
250                         XmlDictionaryString dictNS)
251                 {
252                         reader.MoveToContent ();
253                         if (reader.NodeType != XmlNodeType.Element ||
254                             reader.IsEmptyElement)
255                                 throw new ArgumentException ("Cannot detect appropriate WS-Addressing Address element.");
256
257                         if (localName != null)
258                                 reader.ReadStartElement (localName, ns);
259                         else if (dictLocalName != null)
260                                 ((XmlDictionaryReader) reader).ReadStartElement (dictLocalName, dictNS);
261                         else
262                                 reader.ReadStartElement ();
263                         reader.MoveToContent ();
264
265                         if (addressingVersion == null) {
266                                 if (reader.NamespaceURI == AddressingVersion.WSAddressing10.Namespace)
267                                         addressingVersion = AddressingVersion.WSAddressing10;
268                                 else
269                                 if (reader.NamespaceURI == AddressingVersion.WSAddressingAugust2004.Namespace)
270                                         addressingVersion = AddressingVersion.WSAddressingAugust2004;
271                                 else
272                                         throw new ArgumentException ("Cannot detect appropriate WS-Addressing version.");
273                         }
274
275                         EndpointAddress ea = ReadContents (addressingVersion, reader);
276
277                         reader.MoveToContent ();
278                         reader.ReadEndElement ();
279                         return ea;
280                 }
281                 
282                 private static EndpointAddress ReadContents (
283                         AddressingVersion addressingVersion, XmlReader reader)
284                 {
285                         Uri uri = null;
286                         EndpointIdentity identity = null;
287                         reader.MoveToContent ();
288                         if (reader.LocalName == "Address" && 
289                             reader.NamespaceURI == addressingVersion.Namespace &&
290                             reader.NodeType == XmlNodeType.Element &&
291                             !reader.IsEmptyElement)
292                                 uri = new Uri (reader.ReadElementContentAsString ());
293                         else
294                                 throw new XmlException (String.Format (
295                                         "Expecting 'Address' from namespace '{0}', but found '{1}' from namespace '{2}'",
296                                         addressingVersion.Namespace, reader.LocalName, reader.NamespaceURI));
297
298                         reader.MoveToContent ();
299 #if !MOBILE
300                         MetadataSet metadata = null;
301                         if (reader.LocalName == "Metadata" &&
302                             reader.NamespaceURI == addressingVersion.Namespace &&
303                             !reader.IsEmptyElement) {
304                                 reader.Read ();
305                                 metadata = (MetadataSet) new XmlSerializer (typeof (MetadataSet)).Deserialize (reader);
306                                 reader.MoveToContent ();
307                                 reader.ReadEndElement ();
308                         }
309                         reader.MoveToContent ();
310                         if (reader.LocalName == "Identity" &&
311                             reader.NamespaceURI == Constants.WsaIdentityUri) {
312                                 // FIXME: implement
313                                 reader.Skip ();
314                         }
315 #endif
316
317                         if (addressingVersion == AddressingVersion.WSAddressing10 && uri == w3c_anonymous)
318                                 uri = anonymous_role;
319
320 #if MOBILE
321                         return new EndpointAddress (uri, identity);
322 #else
323                         if (metadata == null)
324                                 return new EndpointAddress (uri, identity);
325                         return new EndpointAddress (uri, identity,
326                                 AddressHeader.CreateAddressHeader (metadata));
327 #endif
328                 }
329
330                 public override string ToString ()
331                 {
332                         return address.ToString (); 
333                 }
334
335                 public void WriteContentsTo (
336                         AddressingVersion addressingVersion,
337                         XmlDictionaryWriter writer)
338                 {
339                         if (writer == null)
340                                 throw new ArgumentNullException ("writer");
341 #if MOBILE
342                         if (addressingVersion == AddressingVersion.None) {
343                                 writer.WriteString (Uri.AbsoluteUri);
344                         } else {
345                                 writer.WriteStartElement ("Address", addressingVersion.Namespace);
346                                 writer.WriteString (Uri.AbsoluteUri);
347                                 writer.WriteEndElement ();
348                         }
349 #else
350                         if (addressingVersion == AddressingVersion.None)
351                                 writer.WriteString (Uri.AbsoluteUri);
352                         else {
353                                 writer.WriteStartElement ("Address", addressingVersion.Namespace);
354                                 writer.WriteString (Uri.AbsoluteUri);
355                                 writer.WriteEndElement ();
356
357                                 if (Identity == null)
358                                         return;
359
360                                 if (Headers != null)
361                                         foreach (AddressHeader ah in Headers)
362                                                 ah.WriteAddressHeader (writer);
363
364                                 writer.WriteStartElement ("Identity", Constants.WsaIdentityUri);
365
366                                 X509CertificateEndpointIdentity x509 =
367                                         Identity as X509CertificateEndpointIdentity;
368                                 if (x509 != null) {
369                                         KeyInfo ki = new KeyInfo ();
370                                         KeyInfoX509Data x = new KeyInfoX509Data ();
371                                         foreach (X509Certificate2 cert in x509.Certificates)
372                                                 x.AddCertificate (cert);
373                                         ki.AddClause (x);
374                                         ki.GetXml ().WriteTo (writer);
375                                 } else {
376                                         DataContractSerializer ds = new DataContractSerializer (Identity.IdentityClaim.GetType ());
377                                         ds.WriteObject (writer, Identity.IdentityClaim);
378                                 }
379                                 writer.WriteEndElement ();
380                         }
381 #endif
382                 }
383
384                 public void WriteContentsTo (
385                         AddressingVersion addressingVersion,
386                         XmlWriter writer)
387                 {
388                         WriteContentsTo (addressingVersion,
389                                 XmlDictionaryWriter.CreateDictionaryWriter (writer));
390                 }
391
392                 public void WriteTo (
393                         AddressingVersion addressingVersion,
394                         XmlDictionaryWriter writer)
395                 {
396                         WriteTo (addressingVersion, writer, "EndpointReference", addressingVersion.Namespace);
397                 }
398
399                 public void WriteTo (
400                         AddressingVersion addressingVersion, XmlWriter writer)
401                 {
402                         WriteTo (addressingVersion,
403                                 XmlDictionaryWriter.CreateDictionaryWriter (writer));
404                 }
405
406                 public void WriteTo (
407                         AddressingVersion addressingVersion,
408                         XmlDictionaryWriter writer,
409                         XmlDictionaryString localname,
410                         XmlDictionaryString ns)
411                 {
412                         writer.WriteStartElement (localname, ns);
413                         WriteContentsTo (addressingVersion, writer);
414                         writer.WriteEndElement ();
415                 }
416
417                 public void WriteTo (
418                         AddressingVersion addressingVersion,
419                         XmlWriter writer, string localname, string ns)
420                 {
421                         writer.WriteStartElement (localname, ns);
422                         WriteContentsTo (addressingVersion, writer);
423                         writer.WriteEndElement ();
424                 }
425         }
426 }