94b2861243
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
333 lines
11 KiB
C#
333 lines
11 KiB
C#
//
|
|
// System.ServiceModel.MessageHeader.cs
|
|
//
|
|
// Author: Duncan Mak (duncan@novell.com)
|
|
// Atsushi Enomoto (atsushi@ximian.com)
|
|
//
|
|
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Runtime.Serialization;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Channels;
|
|
using System.Text;
|
|
using System.Xml;
|
|
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
public abstract class MessageHeader : MessageHeaderInfo
|
|
{
|
|
static readonly XmlWriterSettings writer_settings;
|
|
|
|
static MessageHeader ()
|
|
{
|
|
writer_settings = new XmlWriterSettings ();
|
|
writer_settings.OmitXmlDeclaration = true;
|
|
writer_settings.Indent = true;
|
|
}
|
|
|
|
protected MessageHeader () {}
|
|
|
|
static string default_actor = String.Empty;
|
|
static bool default_is_ref = false;
|
|
static bool default_must_understand = false;
|
|
static bool default_relay = false;
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value)
|
|
{
|
|
return CreateHeader (name, ns, value, default_must_understand);
|
|
}
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value, bool mustUnderstand)
|
|
{
|
|
return CreateHeader (name, ns, value, mustUnderstand, default_actor);
|
|
}
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer)
|
|
{
|
|
return CreateHeader (name, ns, value, serializer, default_must_understand,
|
|
default_actor, default_relay);
|
|
}
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value,
|
|
bool mustUnderstand, string actor)
|
|
{
|
|
return CreateHeader (name, ns, value, mustUnderstand, actor, default_relay);
|
|
}
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer,
|
|
bool mustUnderstand)
|
|
{
|
|
return CreateHeader (name, ns, value, serializer, mustUnderstand, default_actor, default_relay);
|
|
}
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value,
|
|
bool mustUnderstand, string actor, bool relay)
|
|
{
|
|
return CreateHeader (name, ns, value, new DataContractSerializer (value.GetType ()),
|
|
mustUnderstand, actor, relay);
|
|
}
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer,
|
|
bool mustUnderstand, string actor)
|
|
{
|
|
return CreateHeader (name, ns, value, serializer, mustUnderstand, actor, default_relay);
|
|
}
|
|
|
|
public static MessageHeader CreateHeader (string name, string ns, object value, XmlObjectSerializer serializer,
|
|
bool mustUnderstand, string actor, bool relay)
|
|
{
|
|
// FIXME: how to get IsReferenceParameter ?
|
|
return new DefaultMessageHeader (name, ns, value, serializer, default_is_ref, mustUnderstand, actor, relay);
|
|
}
|
|
|
|
public virtual bool IsMessageVersionSupported (MessageVersion messageVersion)
|
|
{
|
|
if (messageVersion.Envelope == EnvelopeVersion.Soap12)
|
|
if (Actor == EnvelopeVersion.Soap11.NextDestinationActorValue)
|
|
return false;
|
|
|
|
if (messageVersion.Envelope == EnvelopeVersion.Soap11)
|
|
if (Actor == EnvelopeVersion.Soap12.NextDestinationActorValue ||
|
|
Actor == EnvelopeVersion.Soap12UltimateReceiver)
|
|
return false;
|
|
|
|
// by default, it's always supported
|
|
return true;
|
|
}
|
|
|
|
protected abstract void OnWriteHeaderContents (XmlDictionaryWriter writer, MessageVersion messageVersion);
|
|
|
|
protected virtual void OnWriteStartHeader (XmlDictionaryWriter writer, MessageVersion messageVersion)
|
|
{
|
|
var dic = Constants.SoapDictionary;
|
|
XmlDictionaryString name, ns;
|
|
var prefix = Prefix ?? (Namespace.Length > 0 ? writer.LookupPrefix (Namespace) : String.Empty);
|
|
if (dic.TryLookup (Name, out name) && dic.TryLookup (Namespace, out ns))
|
|
writer.WriteStartElement (prefix, name, ns);
|
|
else
|
|
writer.WriteStartElement (prefix, this.Name, this.Namespace);
|
|
WriteHeaderAttributes (writer, messageVersion);
|
|
}
|
|
|
|
public override string ToString ()
|
|
{
|
|
StringBuilder sb = new StringBuilder ();
|
|
|
|
XmlWriter w = XmlWriter.Create (sb, writer_settings);
|
|
|
|
WriteHeader (w, MessageVersion.Default);
|
|
w.Close ();
|
|
|
|
return sb.ToString ();
|
|
}
|
|
|
|
public void WriteHeader (XmlDictionaryWriter writer, MessageVersion messageVersion)
|
|
{
|
|
if (writer == null)
|
|
throw new ArgumentNullException ("writer is null.");
|
|
|
|
if (messageVersion == null)
|
|
throw new ArgumentNullException ("messageVersion is null.");
|
|
|
|
if (messageVersion.Envelope == EnvelopeVersion.None)
|
|
return;
|
|
|
|
WriteStartHeader (writer, messageVersion);
|
|
WriteHeaderContents (writer, messageVersion);
|
|
|
|
writer.WriteEndElement ();
|
|
}
|
|
|
|
public void WriteHeader (XmlWriter writer, MessageVersion messageVersion)
|
|
{
|
|
WriteHeader (XmlDictionaryWriter.CreateDictionaryWriter (writer), messageVersion);
|
|
}
|
|
|
|
protected void WriteHeaderAttributes (XmlDictionaryWriter writer, MessageVersion messageVersion)
|
|
{
|
|
var dic = Constants.SoapDictionary;
|
|
if (Id != null)
|
|
writer.WriteAttributeString ("u", dic.Add ("Id"), dic.Add (Constants.WsuNamespace), Id);
|
|
if (!String.IsNullOrEmpty (Actor)) {
|
|
if (messageVersion.Envelope == EnvelopeVersion.Soap11)
|
|
writer.WriteAttributeString ("s", dic.Add ("actor"), dic.Add (messageVersion.Envelope.Namespace), Actor);
|
|
|
|
if (messageVersion.Envelope == EnvelopeVersion.Soap12)
|
|
writer.WriteAttributeString ("s", dic.Add ("role"), dic.Add (messageVersion.Envelope.Namespace), Actor);
|
|
}
|
|
|
|
// mustUnderstand is the same across SOAP 1.1 and 1.2
|
|
if (MustUnderstand == true)
|
|
writer.WriteAttributeString ("s", dic.Add ("mustUnderstand"), dic.Add (messageVersion.Envelope.Namespace), "1");
|
|
|
|
// relay is only available on SOAP 1.2
|
|
if (Relay == true && messageVersion.Envelope == EnvelopeVersion.Soap12)
|
|
writer.WriteAttributeString ("s", dic.Add ("relay"), dic.Add (messageVersion.Envelope.Namespace), "true");
|
|
}
|
|
|
|
public void WriteHeaderContents (XmlDictionaryWriter writer, MessageVersion messageVersion)
|
|
{
|
|
this.OnWriteHeaderContents (writer, messageVersion);
|
|
}
|
|
|
|
public void WriteStartHeader (XmlDictionaryWriter writer, MessageVersion messageVersion)
|
|
{
|
|
this.OnWriteStartHeader (writer, messageVersion);
|
|
}
|
|
|
|
public override string Actor { get { return default_actor; }}
|
|
|
|
public override bool IsReferenceParameter { get { return default_is_ref; }}
|
|
|
|
public override bool MustUnderstand { get { return default_must_understand; }}
|
|
|
|
public override bool Relay { get { return default_relay; }}
|
|
|
|
internal class XmlMessageHeader : MessageHeader
|
|
{
|
|
bool is_ref, must_understand, relay;
|
|
string actor;
|
|
#if MOBILE
|
|
string body;
|
|
#else
|
|
// This is required to completely clone body xml that
|
|
// does not introduce additional xmlns declarations that
|
|
// blocks canonicalized copy of the input XML.
|
|
XmlDocument body;
|
|
#endif
|
|
string local_name;
|
|
string namespace_uri;
|
|
|
|
public XmlMessageHeader (XmlReader reader, MessageVersion version)
|
|
{
|
|
var soapNS = version.Envelope.Namespace;
|
|
var addrNS = version.Addressing.Namespace;
|
|
Prefix = reader.Prefix;
|
|
Id = reader.GetAttribute ("Id", Constants.WsuNamespace);
|
|
|
|
string s = reader.GetAttribute ("relay", soapNS);
|
|
relay = s != null ? XmlConvert.ToBoolean (s) : false;
|
|
s = reader.GetAttribute ("mustUnderstand", soapNS);
|
|
must_understand = s != null ? XmlConvert.ToBoolean (s) : false;
|
|
actor = reader.GetAttribute ("actor", soapNS) ?? String.Empty;
|
|
|
|
s = reader.GetAttribute ("IsReferenceParameter", addrNS);
|
|
is_ref = s != null ? XmlConvert.ToBoolean (s) : false;
|
|
|
|
local_name = reader.LocalName;
|
|
namespace_uri = reader.NamespaceURI;
|
|
#if MOBILE
|
|
body = reader.ReadOuterXml ();
|
|
#else
|
|
body = new XmlDocument ();
|
|
var w = body.CreateNavigator ().AppendChild ();
|
|
w.WriteNode (reader, false);
|
|
w.Close ();
|
|
#endif
|
|
}
|
|
|
|
public XmlReader CreateReader ()
|
|
{
|
|
#if MOBILE
|
|
var reader = XmlReader.Create (new StringReader (body));
|
|
#else
|
|
var reader = new XmlNodeReader (body);
|
|
#endif
|
|
reader.MoveToContent ();
|
|
return reader;
|
|
}
|
|
|
|
protected override void OnWriteHeaderContents (
|
|
XmlDictionaryWriter writer, MessageVersion version)
|
|
{
|
|
var r = CreateReader ();
|
|
r.MoveToContent ();
|
|
if (r.IsEmptyElement)
|
|
return; // write nothing
|
|
for (r.Read (); r.NodeType != XmlNodeType.EndElement;)
|
|
writer.WriteNode (r, false);
|
|
}
|
|
|
|
public override string Actor { get { return actor; }}
|
|
|
|
public override bool IsReferenceParameter { get { return is_ref; }}
|
|
|
|
public override bool MustUnderstand { get { return must_understand; }}
|
|
|
|
public override string Name { get { return local_name; }}
|
|
|
|
public override string Namespace { get { return namespace_uri; }}
|
|
|
|
public override bool Relay { get { return relay; }}
|
|
}
|
|
|
|
internal class DefaultMessageHeader : MessageHeader
|
|
{
|
|
string actor, name, ns;
|
|
object value;
|
|
XmlObjectSerializer formatter;
|
|
bool is_ref, must_understand, relay;
|
|
|
|
internal DefaultMessageHeader (string name, string ns, object value, XmlObjectSerializer formatter,
|
|
bool isReferenceParameter,
|
|
bool mustUnderstand, string actor, bool relay)
|
|
{
|
|
this.name = name;
|
|
this.ns = ns;
|
|
this.value = value;
|
|
this.formatter = formatter;
|
|
this.is_ref = isReferenceParameter;
|
|
this.must_understand = mustUnderstand;
|
|
this.actor = actor ?? String.Empty;
|
|
this.relay = relay;
|
|
}
|
|
|
|
protected override void OnWriteHeaderContents (XmlDictionaryWriter writer,
|
|
MessageVersion version)
|
|
{
|
|
// FIXME: it's a nasty workaround just to avoid UniqueId output as a string, for bug #577139.
|
|
if (Value is UniqueId)
|
|
writer.WriteValue ((UniqueId) Value);
|
|
else
|
|
this.formatter.WriteObjectContent (writer, value);
|
|
}
|
|
|
|
public object Value { get { return value; } }
|
|
|
|
public override string Actor { get { return actor; }}
|
|
|
|
public override bool IsReferenceParameter { get { return is_ref; }}
|
|
|
|
public override bool MustUnderstand { get { return must_understand; }}
|
|
|
|
public override string Name { get { return name; }}
|
|
|
|
public override string Namespace { get { return ns; }}
|
|
|
|
public override bool Relay { get { return relay; }}
|
|
}
|
|
}
|
|
}
|