2014-08-13 10:39:27 +01:00
//
// System.ServiceModel.MessageHeader.cs
//
// Author: Duncan Mak (duncan@novell.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.Collections ;
using System.Collections.Generic ;
using System.IO ;
using System.Runtime.Serialization ;
using System.ServiceModel ;
using System.Xml ;
namespace System.ServiceModel.Channels
{
public sealed class MessageHeaders : IEnumerable < MessageHeaderInfo > , IEnumerable
{
static readonly XmlReaderSettings reader_settings ;
static MessageHeaders ( )
{
reader_settings = new XmlReaderSettings ( ) ;
reader_settings . ConformanceLevel = ConformanceLevel . Fragment ;
}
List < MessageHeaderInfo > l ;
Dictionary < Type , XmlObjectSerializer > serializers =
new Dictionary < Type , XmlObjectSerializer > ( ) ;
MessageVersion version ;
2017-06-07 13:16:24 +00:00
public MessageHeaders ( MessageHeaders collection )
: this ( collection . MessageVersion )
2014-08-13 10:39:27 +01:00
{
2017-06-07 13:16:24 +00:00
CopyHeadersFrom ( collection ) ;
2014-08-13 10:39:27 +01:00
}
public MessageHeaders ( MessageVersion version )
: this ( version , 10 ) // let's say 10 is the initial size
{
}
2017-06-07 13:16:24 +00:00
public MessageHeaders ( MessageVersion version , int initialSize )
2014-08-13 10:39:27 +01:00
{
this . version = version ;
2017-06-07 13:16:24 +00:00
l = new List < MessageHeaderInfo > ( initialSize ) ;
2014-08-13 10:39:27 +01:00
}
public void Add ( MessageHeader header )
{
l . Add ( header ) ;
}
2016-09-01 10:46:18 +00:00
public void CopyHeaderFrom ( Message message , int headerIndex )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
CopyHeaderFrom ( message . Headers , headerIndex ) ;
2014-08-13 10:39:27 +01:00
}
public void Clear ( )
{
l . Clear ( ) ;
}
2016-09-01 10:46:18 +00:00
public void CopyHeaderFrom ( MessageHeaders collection , int headerIndex )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
l . Add ( collection [ headerIndex ] ) ;
2014-08-13 10:39:27 +01:00
}
2016-09-01 10:46:18 +00:00
public void CopyHeadersFrom ( Message message )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
CopyHeadersFrom ( message . Headers ) ;
2014-08-13 10:39:27 +01:00
}
2016-09-01 10:46:18 +00:00
public void CopyHeadersFrom ( MessageHeaders collection )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
foreach ( MessageHeaderInfo h in collection )
2014-08-13 10:39:27 +01:00
l . Add ( h ) ;
}
2016-09-01 10:46:18 +00:00
public void CopyTo ( MessageHeaderInfo [ ] array , int index )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
l . CopyTo ( array , index ) ;
2014-08-13 10:39:27 +01:00
}
public int FindHeader ( string name , string ns )
{
return FindHeader ( name , ns , null ) ;
}
bool HasActor ( string actor , string [ ] candidates )
{
foreach ( string c in candidates )
if ( c = = actor )
return true ;
return false ;
}
public int FindHeader ( string name , string ns , params string [ ] actors )
{
int found = 0 ;
int retval = - 1 ;
for ( int i = 0 ; i < l . Count ; i + + ) {
MessageHeaderInfo info = l [ i ] ;
if ( info . Name = = name & & info . Namespace = = ns ) {
if ( found > 0 )
throw new MessageHeaderException ( "Found multiple matching headers." ) ;
// When no actors are passed, it never
// matches such header that has an
// Actor.
if ( actors = = null & & info . Actor = = String . Empty | |
actors ! = null & & HasActor ( info . Actor , actors ) ) {
retval = i ;
found + + ;
}
}
}
return retval ;
}
public IEnumerator < MessageHeaderInfo > GetEnumerator ( )
{
return l . GetEnumerator ( ) ;
}
XmlObjectSerializer GetSerializer < T > ( int headerIndex )
{
if ( ! serializers . ContainsKey ( typeof ( T ) ) )
serializers [ typeof ( T ) ] = new DataContractSerializer ( typeof ( T ) , this [ headerIndex ] . Name , this [ headerIndex ] . Namespace ) ;
return serializers [ typeof ( T ) ] ;
}
public T GetHeader < T > ( int index )
{
if ( l . Count < = index )
throw new ArgumentOutOfRangeException ( "index" ) ;
var dmh = l [ index ] as MessageHeader . DefaultMessageHeader ;
if ( dmh ! = null & & dmh . Value ! = null & & typeof ( T ) . IsAssignableFrom ( dmh . Value . GetType ( ) ) )
return ( T ) dmh . Value ;
if ( typeof ( T ) = = typeof ( EndpointAddress ) ) {
XmlDictionaryReader r = GetReaderAtHeader ( index ) ;
return r . NodeType ! = XmlNodeType . Element ? default ( T ) : ( T ) ( object ) EndpointAddress . ReadFrom ( r ) ;
}
else
return GetHeader < T > ( index , GetSerializer < T > ( index ) ) ;
}
public T GetHeader < T > ( int index , XmlObjectSerializer serializer )
{
if ( serializer = = null )
throw new ArgumentNullException ( "serializer" ) ;
XmlDictionaryReader r = GetReaderAtHeader ( index ) ;
return ( T ) serializer . ReadObject ( r , false ) ;
}
public T GetHeader < T > ( string name , string ns )
{
return GetHeader < T > ( name , ns , ( string [ ] ) null ) ;
}
public T GetHeader < T > ( string name , string ns , params string [ ] actors )
{
int idx = FindHeader ( name , ns , actors ) ;
if ( idx = = - 1 )
throw new MessageHeaderException ( String . Format ( "Header '{0}:{1}' was not found for the argument actors: {2}" , ns , name , actors = = null ? "(null)" : String . Join ( "," , actors ) ) ) ;
return GetHeader < T > ( idx ) ;
}
public T GetHeader < T > ( string name , string ns , XmlObjectSerializer serializer )
{
if ( serializer = = null )
throw new ArgumentNullException ( "serializer" ) ;
int idx = FindHeader ( name , ns ) ;
if ( idx < 0 )
throw new MessageHeaderException ( String . Format ( "Header '{0}:{1}' was not found" , ns , name ) ) ;
return GetHeader < T > ( idx , serializer ) ;
}
2016-09-01 10:46:18 +00:00
public XmlDictionaryReader GetReaderAtHeader ( int headerIndex )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
if ( headerIndex > = l . Count )
throw new ArgumentOutOfRangeException ( String . Format ( "Index is out of range. Current header count is {0}" , l . Count ) ) ;
MessageHeader item = ( MessageHeader ) l [ headerIndex ] ;
2014-08-13 10:39:27 +01:00
XmlReader reader =
item is MessageHeader . XmlMessageHeader ?
( ( MessageHeader . XmlMessageHeader ) item ) . CreateReader ( ) :
XmlReader . Create (
new StringReader ( item . ToString ( ) ) ,
reader_settings ) ;
reader . MoveToContent ( ) ;
XmlDictionaryReader dr = XmlDictionaryReader . CreateDictionaryReader ( reader ) ;
dr . MoveToContent ( ) ;
return dr ;
}
public bool HaveMandatoryHeadersBeenUnderstood ( )
{
throw new NotImplementedException ( ) ;
}
public bool HaveMandatoryHeadersBeenUnderstood ( params string [ ] actors )
{
throw new NotImplementedException ( ) ;
}
2016-09-01 10:46:18 +00:00
public void Insert ( int headerIndex , MessageHeader header )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
l . Insert ( headerIndex , header ) ;
2014-08-13 10:39:27 +01:00
}
public void RemoveAll ( string name , string ns )
{
// Shuffle all the ones we want to keep to the start of the list
int j = 0 ;
for ( int i = 0 ; i < l . Count ; i + + ) {
if ( l [ i ] . Name ! = name | | l [ i ] . Namespace ! = ns ) {
l [ j + + ] = l [ i ] ;
}
}
// Trim the extra elements off the end of the list.
int count = l . Count - j ;
for ( int i = 0 ; i < count ; i + + )
l . RemoveAt ( l . Count - 1 ) ;
}
2016-09-01 10:46:18 +00:00
public void RemoveAt ( int headerIndex )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
l . RemoveAt ( headerIndex ) ;
2014-08-13 10:39:27 +01:00
}
IEnumerator IEnumerable . GetEnumerator ( )
{
return ( ( IEnumerable ) l ) . GetEnumerator ( ) ;
}
2016-09-01 10:46:18 +00:00
public void WriteHeader ( int headerIndex , XmlDictionaryWriter writer )
2014-08-13 10:39:27 +01:00
{
if ( version . Envelope = = EnvelopeVersion . None )
return ;
2016-09-01 10:46:18 +00:00
WriteStartHeader ( headerIndex , writer ) ;
WriteHeaderContents ( headerIndex , writer ) ;
2014-08-13 10:39:27 +01:00
writer . WriteEndElement ( ) ;
}
2016-09-01 10:46:18 +00:00
public void WriteHeader ( int headerIndex , XmlWriter writer )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
WriteHeader ( headerIndex , XmlDictionaryWriter . CreateDictionaryWriter ( writer ) ) ;
2014-08-13 10:39:27 +01:00
}
2016-09-01 10:46:18 +00:00
public void WriteHeaderContents ( int headerIndex , XmlDictionaryWriter writer )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
if ( headerIndex > l . Count )
throw new ArgumentOutOfRangeException ( "There is no header at position " + headerIndex + "." ) ;
2014-08-13 10:39:27 +01:00
2016-09-01 10:46:18 +00:00
MessageHeader h = l [ headerIndex ] as MessageHeader ;
2014-08-13 10:39:27 +01:00
h . WriteHeaderContents ( writer , version ) ;
}
2016-09-01 10:46:18 +00:00
public void WriteHeaderContents ( int headerIndex , XmlWriter writer )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
WriteHeaderContents ( headerIndex , XmlDictionaryWriter . CreateDictionaryWriter ( writer ) ) ;
2014-08-13 10:39:27 +01:00
}
2016-09-01 10:46:18 +00:00
public void WriteStartHeader ( int headerIndex , XmlDictionaryWriter writer )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
if ( headerIndex > l . Count )
throw new ArgumentOutOfRangeException ( "There is no header at position " + headerIndex + "." ) ;
2014-08-13 10:39:27 +01:00
2016-09-01 10:46:18 +00:00
MessageHeader h = l [ headerIndex ] as MessageHeader ;
2014-08-13 10:39:27 +01:00
h . WriteStartHeader ( writer , version ) ;
}
2016-09-01 10:46:18 +00:00
public void WriteStartHeader ( int headerIndex , XmlWriter writer )
2014-08-13 10:39:27 +01:00
{
2016-09-01 10:46:18 +00:00
WriteStartHeader ( headerIndex , XmlDictionaryWriter . CreateDictionaryWriter ( writer ) ) ;
2014-08-13 10:39:27 +01:00
}
public string Action {
get {
int idx = FindHeader ( "Action" , version . Addressing . Namespace ) ;
return idx < 0 ? null : GetHeader < string > ( idx ) ;
}
set {
RemoveAll ( "Action" , version . Addressing . Namespace ) ;
if ( value ! = null )
Add ( MessageHeader . CreateHeader ( "Action" , version . Addressing . Namespace , value , true ) ) ;
}
}
public int Count {
get { return l . Count ; }
}
void AddEndpointAddressHeader ( string name , string ns , EndpointAddress address )
{
if ( address = = null )
return ;
if ( MessageVersion . Addressing . Equals ( AddressingVersion . WSAddressing10 ) )
Add ( MessageHeader . CreateHeader ( name , ns , EndpointAddress10 . FromEndpointAddress ( address ) ) ) ;
2016-11-10 13:04:39 +00:00
#if ! MOBILE
2014-08-13 10:39:27 +01:00
else if ( MessageVersion . Addressing . Equals ( AddressingVersion . WSAddressingAugust2004 ) )
Add ( MessageHeader . CreateHeader ( name , ns , EndpointAddressAugust2004 . FromEndpointAddress ( address ) ) ) ;
#endif
else
throw new InvalidOperationException ( "WS-Addressing header is not allowed for AddressingVersion.None" ) ;
}
public EndpointAddress FaultTo {
get {
int idx = FindHeader ( "FaultTo" , version . Addressing . Namespace ) ;
return idx < 0 ? null : GetHeader < EndpointAddress > ( idx ) ;
}
set {
RemoveAll ( "FaultTo" , version . Addressing . Namespace ) ;
if ( value ! = null )
AddEndpointAddressHeader ( "FaultTo" , version . Addressing . Namespace , value ) ;
}
}
public EndpointAddress From {
get {
int idx = FindHeader ( "From" , version . Addressing . Namespace ) ;
return idx < 0 ? null : GetHeader < EndpointAddress > ( idx ) ;
}
set {
RemoveAll ( "From" , version . Addressing . Namespace ) ;
if ( value ! = null )
AddEndpointAddressHeader ( "From" , version . Addressing . Namespace , value ) ;
}
}
public MessageHeaderInfo this [ int index ] {
get { return l [ index ] ; }
}
public UniqueId MessageId {
get {
int idx = FindHeader ( "MessageID" , version . Addressing . Namespace ) ;
return idx < 0 ? null : new UniqueId ( GetHeader < string > ( idx ) ) ;
}
set {
if ( version . Addressing = = AddressingVersion . None & & value ! = null )
throw new InvalidOperationException ( "WS-Addressing header is not allowed for AddressingVersion.None" ) ;
RemoveAll ( "MessageID" , version . Addressing . Namespace ) ;
if ( value ! = null )
Add ( MessageHeader . CreateHeader ( "MessageID" , version . Addressing . Namespace , value ) ) ;
}
}
public MessageVersion MessageVersion { get { return version ; } }
public UniqueId RelatesTo {
get {
int idx = FindHeader ( "RelatesTo" , version . Addressing . Namespace ) ;
return idx < 0 ? null : new UniqueId ( GetHeader < string > ( idx ) ) ;
}
set {
if ( version . Addressing = = AddressingVersion . None & & value ! = null )
throw new InvalidOperationException ( "WS-Addressing header is not allowed for AddressingVersion.None" ) ;
RemoveAll ( "MessageID" , version . Addressing . Namespace ) ;
if ( value ! = null )
Add ( MessageHeader . CreateHeader ( "RelatesTo" , version . Addressing . Namespace , value ) ) ;
}
}
public EndpointAddress ReplyTo {
get {
int idx = FindHeader ( "ReplyTo" , version . Addressing . Namespace ) ;
return idx < 0 ? null : GetHeader < EndpointAddress > ( idx ) ;
}
set {
RemoveAll ( "ReplyTo" , version . Addressing . Namespace ) ;
if ( value ! = null )
AddEndpointAddressHeader ( "ReplyTo" , version . Addressing . Namespace , value ) ;
}
}
public Uri To {
get {
int idx = FindHeader ( "To" , version . Addressing . Namespace ) ;
//FIXME: return idx < 0 ? null : GetHeader<Uri> (idx);
return idx < 0 ? null : new Uri ( GetHeader < string > ( idx ) ) ;
}
set {
RemoveAll ( "To" , version . Addressing . Namespace ) ;
if ( value ! = null )
Add ( MessageHeader . CreateHeader ( "To" , version . Addressing . Namespace , value . AbsoluteUri , true ) ) ;
}
}
[MonoTODO]
public UnderstoodHeaders UnderstoodHeaders {
get { throw new NotImplementedException ( ) ; }
}
public void SetAction ( XmlDictionaryString action )
{
if ( action = = null )
Action = null ;
else
Action = action . Value ;
}
}
}