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 EndpointAddress(string uri)68 public EndpointAddress (string uri) 69 : this (new Uri (uri), new AddressHeader [0]) 70 { 71 } 72 EndpointAddress(Uri uri, params AddressHeader [] addressHeaders)73 public EndpointAddress (Uri uri, params AddressHeader [] addressHeaders) 74 : this (uri, null, new AddressHeaderCollection (addressHeaders), null, null) {} 75 EndpointAddress(Uri uri, EndpointIdentity identity, params AddressHeader [] addressHeaders)76 public EndpointAddress (Uri uri, EndpointIdentity identity, params AddressHeader [] addressHeaders) 77 : this (uri, identity, new AddressHeaderCollection (addressHeaders), null, null) {} 78 EndpointAddress(Uri uri, EndpointIdentity identity, AddressHeaderCollection headers)79 public EndpointAddress (Uri uri, EndpointIdentity identity, AddressHeaderCollection headers) 80 : this (uri, identity, headers, null, null) {} 81 EndpointAddress( Uri uri, EndpointIdentity identity, AddressHeaderCollection headers, XmlDictionaryReader metadataReader, XmlDictionaryReader extensionReader)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] ApplyTo(Message message)134 public void ApplyTo (Message message) 135 { 136 throw new NotImplementedException (); 137 } 138 Equals(object obj)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 GetHashCode()161 public override int GetHashCode () 162 { 163 return address.GetHashCode (); 164 } 165 GetReaderAtExtensions()166 public XmlDictionaryReader GetReaderAtExtensions () 167 { 168 return extension_reader; 169 } 170 GetReaderAtMetadata()171 public XmlDictionaryReader GetReaderAtMetadata () 172 { 173 return metadata_reader; 174 } 175 operator ==(EndpointAddress address1, EndpointAddress address2)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 operator !=(EndpointAddress address1, EndpointAddress address2)185 public static bool operator != (EndpointAddress address1, EndpointAddress address2) 186 { 187 return ! (address1 == address2); 188 } 189 190 //#if !MOBILE ReadFrom( XmlDictionaryReader reader)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 ReadFrom( AddressingVersion addressingVersion, XmlDictionaryReader reader)200 public static EndpointAddress ReadFrom ( 201 AddressingVersion addressingVersion, 202 XmlDictionaryReader reader) 203 { 204 return ReadFrom (addressingVersion, (XmlReader) reader); 205 } 206 ReadFrom( AddressingVersion addressingVersion, XmlReader reader)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 ReadFrom( XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)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 ReadFrom( AddressingVersion addressingVersion, XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)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 ReadFrom( AddressingVersion addressingVersion, XmlReader reader, string localName, string ns)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 ReadFromInternal( AddressingVersion addressingVersion, XmlReader reader, string localName, string ns, XmlDictionaryString dictLocalName, XmlDictionaryString dictNS)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 ReadContents( AddressingVersion addressingVersion, XmlReader reader)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 ToString()330 public override string ToString () 331 { 332 return address.ToString (); 333 } 334 WriteContentsTo( AddressingVersion addressingVersion, XmlDictionaryWriter writer)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 WriteContentsTo( AddressingVersion addressingVersion, XmlWriter writer)384 public void WriteContentsTo ( 385 AddressingVersion addressingVersion, 386 XmlWriter writer) 387 { 388 WriteContentsTo (addressingVersion, 389 XmlDictionaryWriter.CreateDictionaryWriter (writer)); 390 } 391 WriteTo( AddressingVersion addressingVersion, XmlDictionaryWriter writer)392 public void WriteTo ( 393 AddressingVersion addressingVersion, 394 XmlDictionaryWriter writer) 395 { 396 WriteTo (addressingVersion, writer, "EndpointReference", addressingVersion.Namespace); 397 } 398 WriteTo( AddressingVersion addressingVersion, XmlWriter writer)399 public void WriteTo ( 400 AddressingVersion addressingVersion, XmlWriter writer) 401 { 402 WriteTo (addressingVersion, 403 XmlDictionaryWriter.CreateDictionaryWriter (writer)); 404 } 405 WriteTo( AddressingVersion addressingVersion, XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns)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 WriteTo( AddressingVersion addressingVersion, XmlWriter writer, string localName, string ns)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 } 427