1 //------------------------------------------------------------ 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //------------------------------------------------------------ 4 namespace System.ServiceModel.Channels 5 { 6 using System.Xml; 7 using System.ServiceModel; 8 using System.ServiceModel.Dispatcher; 9 using System.Xml.XPath; 10 using System.Diagnostics; 11 using System.IO; 12 using System.Collections.Generic; 13 14 public abstract class MessageBuffer : IXPathNavigable, IDisposable 15 { 16 public abstract int BufferSize { get; } 17 IDisposable.Dispose()18 void IDisposable.Dispose() 19 { 20 Close(); 21 } 22 Close()23 public abstract void Close(); 24 WriteMessage(Stream stream)25 public virtual void WriteMessage(Stream stream) 26 { 27 if (stream == null) 28 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream")); 29 Message message = CreateMessage(); 30 using (message) 31 { 32 XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream, XD.Dictionary, null, false); 33 using (writer) 34 { 35 message.WriteMessage(writer); 36 } 37 } 38 } 39 40 public virtual string MessageContentType 41 { 42 get { return FramingEncodingString.Binary; } 43 } 44 CreateMessage()45 public abstract Message CreateMessage(); 46 CreateBufferDisposedException()47 internal Exception CreateBufferDisposedException() 48 { 49 return new ObjectDisposedException("", SR.GetString(SR.MessageBufferIsClosed)); 50 } 51 CreateNavigator()52 public XPathNavigator CreateNavigator() 53 { 54 return CreateNavigator(int.MaxValue, XmlSpace.None); 55 } 56 CreateNavigator(int nodeQuota)57 public XPathNavigator CreateNavigator(int nodeQuota) 58 { 59 return CreateNavigator(nodeQuota, XmlSpace.None); 60 } 61 CreateNavigator(XmlSpace space)62 public XPathNavigator CreateNavigator(XmlSpace space) 63 { 64 return CreateNavigator(int.MaxValue, space); 65 } 66 CreateNavigator(int nodeQuota, XmlSpace space)67 public XPathNavigator CreateNavigator(int nodeQuota, XmlSpace space) 68 { 69 if (nodeQuota <= 0) 70 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("nodeQuota", SR.GetString(SR.FilterQuotaRange))); 71 72 return new SeekableMessageNavigator(this.CreateMessage(), nodeQuota, space, true, true); 73 } 74 } 75 76 class DefaultMessageBuffer : MessageBuffer 77 { 78 XmlBuffer msgBuffer; 79 KeyValuePair<string, object>[] properties; 80 bool[] understoodHeaders; 81 bool closed; 82 MessageVersion version; 83 Uri to; 84 string action; 85 bool isNullMessage; 86 DefaultMessageBuffer(Message message, XmlBuffer msgBuffer)87 public DefaultMessageBuffer(Message message, XmlBuffer msgBuffer) 88 { 89 this.msgBuffer = msgBuffer; 90 this.version = message.Version; 91 this.isNullMessage = message is NullMessage; 92 93 properties = new KeyValuePair<string, object>[message.Properties.Count]; 94 ((ICollection<KeyValuePair<string, object>>)message.Properties).CopyTo(properties, 0); 95 understoodHeaders = new bool[message.Headers.Count]; 96 for (int i = 0; i < understoodHeaders.Length; ++i) 97 understoodHeaders[i] = message.Headers.IsUnderstood(i); 98 99 //CSDMain 17837: CreateBufferedCopy should have code to copy over the To and Action headers 100 if (version == MessageVersion.None) 101 { 102 this.to = message.Headers.To; 103 this.action = message.Headers.Action; 104 } 105 } 106 107 object ThisLock 108 { 109 get { return msgBuffer; } 110 } 111 112 public override int BufferSize 113 { 114 get { return msgBuffer.BufferSize; } 115 } 116 Close()117 public override void Close() 118 { 119 lock (ThisLock) 120 { 121 if (closed) 122 return; 123 124 closed = true; 125 for (int i = 0; i < this.properties.Length; i++) 126 { 127 IDisposable disposable = this.properties[i].Value as IDisposable; 128 if (disposable != null) 129 disposable.Dispose(); 130 } 131 } 132 } 133 CreateMessage()134 public override Message CreateMessage() 135 { 136 if (closed) 137 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException()); 138 139 Message msg; 140 if (this.isNullMessage) 141 { 142 msg = new NullMessage(); 143 } 144 else 145 { 146 msg = Message.CreateMessage(msgBuffer.GetReader(0), int.MaxValue, this.version); 147 } 148 149 lock (ThisLock) 150 { 151 msg.Properties.CopyProperties(properties); 152 } 153 154 for (int i = 0; i < understoodHeaders.Length; ++i) 155 { 156 if (understoodHeaders[i]) 157 msg.Headers.AddUnderstood(i); 158 } 159 160 if (this.to != null) 161 { 162 msg.Headers.To = this.to; 163 } 164 165 if (this.action != null) 166 { 167 msg.Headers.Action = this.action; 168 } 169 170 return msg; 171 } 172 } 173 174 class BufferedMessageBuffer : MessageBuffer 175 { 176 IBufferedMessageData messageData; 177 KeyValuePair<string, object>[] properties; 178 bool closed; 179 object thisLock = new object(); 180 bool[] understoodHeaders; 181 bool understoodHeadersModified; 182 BufferedMessageBuffer(IBufferedMessageData messageData, KeyValuePair<string, object>[] properties, bool[] understoodHeaders, bool understoodHeadersModified)183 public BufferedMessageBuffer(IBufferedMessageData messageData, 184 KeyValuePair<string, object>[] properties, bool[] understoodHeaders, bool understoodHeadersModified) 185 { 186 this.messageData = messageData; 187 this.properties = properties; 188 this.understoodHeaders = understoodHeaders; 189 this.understoodHeadersModified = understoodHeadersModified; 190 messageData.Open(); 191 } 192 193 public override int BufferSize 194 { 195 get 196 { 197 lock (ThisLock) 198 { 199 if (closed) 200 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose 201 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException()); 202 return messageData.Buffer.Count; 203 } 204 } 205 } 206 WriteMessage(Stream stream)207 public override void WriteMessage(Stream stream) 208 { 209 if (stream == null) 210 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream")); 211 lock (ThisLock) 212 { 213 if (closed) 214 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException()); 215 ArraySegment<byte> buffer = messageData.Buffer; 216 stream.Write(buffer.Array, buffer.Offset, buffer.Count); 217 } 218 } 219 220 public override string MessageContentType 221 { 222 get 223 { 224 lock (ThisLock) 225 { 226 if (closed) 227 #pragma warning suppress 56503 // Microsoft, Invalid State after dispose 228 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException()); 229 return messageData.MessageEncoder.ContentType; 230 } 231 } 232 } 233 234 object ThisLock 235 { 236 get { return thisLock; } 237 } 238 Close()239 public override void Close() 240 { 241 lock (ThisLock) 242 { 243 if (!closed) 244 { 245 closed = true; 246 messageData.Close(); 247 messageData = null; 248 } 249 } 250 } 251 CreateMessage()252 public override Message CreateMessage() 253 { 254 lock (ThisLock) 255 { 256 if (closed) 257 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException()); 258 RecycledMessageState recycledMessageState = messageData.TakeMessageState(); 259 if (recycledMessageState == null) 260 recycledMessageState = new RecycledMessageState(); 261 BufferedMessage bufferedMessage = new BufferedMessage(messageData, recycledMessageState, this.understoodHeaders, this.understoodHeadersModified); 262 bufferedMessage.Properties.CopyProperties(this.properties); 263 messageData.Open(); 264 return bufferedMessage; 265 } 266 } 267 } 268 269 class BodyWriterMessageBuffer : MessageBuffer 270 { 271 BodyWriter bodyWriter; 272 KeyValuePair<string, object>[] properties; 273 MessageHeaders headers; 274 bool closed; 275 object thisLock = new object(); 276 BodyWriterMessageBuffer(MessageHeaders headers, KeyValuePair<string, object>[] properties, BodyWriter bodyWriter)277 public BodyWriterMessageBuffer(MessageHeaders headers, 278 KeyValuePair<string, object>[] properties, BodyWriter bodyWriter) 279 { 280 this.bodyWriter = bodyWriter; 281 this.headers = new MessageHeaders(headers); 282 this.properties = properties; 283 } 284 285 protected object ThisLock 286 { 287 get { return thisLock; } 288 } 289 290 public override int BufferSize 291 { 292 get { return 0; } 293 } 294 Close()295 public override void Close() 296 { 297 lock (ThisLock) 298 { 299 if (!closed) 300 { 301 closed = true; 302 bodyWriter = null; 303 headers = null; 304 properties = null; 305 } 306 } 307 } 308 CreateMessage()309 public override Message CreateMessage() 310 { 311 lock (ThisLock) 312 { 313 if (closed) 314 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException()); 315 return new BodyWriterMessage(headers, properties, bodyWriter); 316 } 317 } 318 319 protected BodyWriter BodyWriter 320 { 321 get { return bodyWriter; } 322 } 323 324 protected MessageHeaders Headers 325 { 326 get { return headers; } 327 } 328 329 protected KeyValuePair<string, object>[] Properties 330 { 331 get { return properties; } 332 } 333 334 protected bool Closed 335 { 336 get { return closed; } 337 } 338 } 339 } 340