MtomMessageEncoder.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Globalization;
  7. using System.IO;
  8. using System.Runtime;
  9. using System.ServiceModel;
  10. using System.ServiceModel.Description;
  11. using System.ServiceModel.Diagnostics;
  12. using System.Text;
  13. using System.Threading;
  14. using System.Xml;
  15. using System.ServiceModel.Diagnostics.Application;
  16. using System.Runtime.Diagnostics;
  17. class MtomMessageEncoderFactory : MessageEncoderFactory
  18. {
  19. MtomMessageEncoder messageEncoder;
  20. public MtomMessageEncoderFactory(MessageVersion version, Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, int maxBufferSize, XmlDictionaryReaderQuotas quotas)
  21. {
  22. messageEncoder = new MtomMessageEncoder(version, writeEncoding, maxReadPoolSize, maxWritePoolSize, maxBufferSize, quotas);
  23. }
  24. public override MessageEncoder Encoder
  25. {
  26. get { return messageEncoder; }
  27. }
  28. public override MessageVersion MessageVersion
  29. {
  30. get { return messageEncoder.MessageVersion; }
  31. }
  32. public int MaxWritePoolSize
  33. {
  34. get { return messageEncoder.MaxWritePoolSize; }
  35. }
  36. public int MaxReadPoolSize
  37. {
  38. get { return messageEncoder.MaxReadPoolSize; }
  39. }
  40. public XmlDictionaryReaderQuotas ReaderQuotas
  41. {
  42. get
  43. {
  44. return messageEncoder.ReaderQuotas;
  45. }
  46. }
  47. public int MaxBufferSize
  48. {
  49. get { return messageEncoder.MaxBufferSize; }
  50. }
  51. public static Encoding[] GetSupportedEncodings()
  52. {
  53. Encoding[] supported = TextEncoderDefaults.SupportedEncodings;
  54. Encoding[] enc = new Encoding[supported.Length];
  55. Array.Copy(supported, enc, supported.Length);
  56. return enc;
  57. }
  58. }
  59. // Some notes:
  60. // The Encoding passed in is used for the SOAP envelope
  61. class MtomMessageEncoder : MessageEncoder, ITraceSourceStringProvider
  62. {
  63. Encoding writeEncoding;
  64. // Double-checked locking pattern requires volatile for read/write synchronization
  65. volatile SynchronizedPool<XmlDictionaryWriter> streamedWriterPool;
  66. volatile SynchronizedPool<XmlDictionaryReader> streamedReaderPool;
  67. volatile SynchronizedPool<MtomBufferedMessageData> bufferedReaderPool;
  68. volatile SynchronizedPool<MtomBufferedMessageWriter> bufferedWriterPool;
  69. volatile SynchronizedPool<RecycledMessageState> recycledStatePool;
  70. object thisLock;
  71. MessageVersion version;
  72. const int maxPooledXmlReadersPerMessage = 2;
  73. int maxReadPoolSize;
  74. int maxWritePoolSize;
  75. static UriGenerator mimeBoundaryGenerator;
  76. XmlDictionaryReaderQuotas readerQuotas;
  77. XmlDictionaryReaderQuotas bufferedReadReaderQuotas;
  78. int maxBufferSize;
  79. OnXmlDictionaryReaderClose onStreamedReaderClose;
  80. internal TextMessageEncoderFactory.ContentEncoding[] contentEncodingMap;
  81. const string mtomMediaType = "multipart/related";
  82. const string mtomContentType = mtomMediaType + "; type=\"application/xop+xml\"";
  83. const string mtomStartUri = NamingHelper.DefaultNamespace + "0";
  84. public MtomMessageEncoder(MessageVersion version, Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, int maxBufferSize, XmlDictionaryReaderQuotas quotas)
  85. {
  86. if (version == null)
  87. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
  88. if (writeEncoding == null)
  89. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writeEncoding");
  90. TextEncoderDefaults.ValidateEncoding(writeEncoding);
  91. this.writeEncoding = writeEncoding;
  92. this.maxReadPoolSize = maxReadPoolSize;
  93. this.maxWritePoolSize = maxWritePoolSize;
  94. this.readerQuotas = new XmlDictionaryReaderQuotas();
  95. quotas.CopyTo(this.readerQuotas);
  96. this.bufferedReadReaderQuotas = EncoderHelpers.GetBufferedReadQuotas(this.readerQuotas);
  97. this.maxBufferSize = maxBufferSize;
  98. this.onStreamedReaderClose = new OnXmlDictionaryReaderClose(ReturnStreamedReader);
  99. this.thisLock = new object();
  100. if (version.Envelope == EnvelopeVersion.Soap12)
  101. {
  102. this.contentEncodingMap = TextMessageEncoderFactory.Soap12Content;
  103. }
  104. else if (version.Envelope == EnvelopeVersion.Soap11)
  105. {
  106. this.contentEncodingMap = TextMessageEncoderFactory.Soap11Content;
  107. }
  108. else
  109. {
  110. Fx.Assert("Invalid MessageVersion");
  111. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid MessageVersion")));
  112. }
  113. this.version = version;
  114. }
  115. static UriGenerator MimeBoundaryGenerator
  116. {
  117. get
  118. {
  119. if (mimeBoundaryGenerator == null)
  120. mimeBoundaryGenerator = new UriGenerator("uuid", "+");
  121. return mimeBoundaryGenerator;
  122. }
  123. }
  124. public override string ContentType
  125. {
  126. get { return mtomContentType; }
  127. }
  128. public int MaxWritePoolSize
  129. {
  130. get { return maxWritePoolSize; }
  131. }
  132. public int MaxReadPoolSize
  133. {
  134. get { return maxReadPoolSize; }
  135. }
  136. public XmlDictionaryReaderQuotas ReaderQuotas
  137. {
  138. get
  139. {
  140. return readerQuotas;
  141. }
  142. }
  143. public int MaxBufferSize
  144. {
  145. get { return maxBufferSize; }
  146. }
  147. public override string MediaType
  148. {
  149. get { return mtomMediaType; }
  150. }
  151. public override MessageVersion MessageVersion
  152. {
  153. get { return version; }
  154. }
  155. internal bool IsMTOMContentType(string contentType)
  156. {
  157. // check for MTOM contentType: multipart/related; type=\"application/xop+xml\"
  158. return IsContentTypeSupported(contentType, this.ContentType, this.MediaType);
  159. }
  160. internal bool IsTextContentType(string contentType)
  161. {
  162. // check for Text contentType: text/xml or application/soap+xml
  163. string textMediaType = TextMessageEncoderFactory.GetMediaType(version);
  164. string textContentType = TextMessageEncoderFactory.GetContentType(textMediaType, writeEncoding);
  165. return IsContentTypeSupported(contentType, textContentType, textMediaType);
  166. }
  167. public override bool IsContentTypeSupported(string contentType)
  168. {
  169. if (contentType == null)
  170. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("contentType"));
  171. return (IsMTOMContentType(contentType) || IsTextContentType(contentType));
  172. }
  173. internal override bool IsCharSetSupported(string charSet)
  174. {
  175. if (charSet == null || charSet.Length == 0)
  176. return true;
  177. Encoding tmp;
  178. return TextEncoderDefaults.TryGetEncoding(charSet, out tmp);
  179. }
  180. string GenerateStartInfoString()
  181. {
  182. return (version.Envelope == EnvelopeVersion.Soap12) ? TextMessageEncoderFactory.Soap12MediaType : TextMessageEncoderFactory.Soap11MediaType;
  183. }
  184. public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
  185. {
  186. if (bufferManager == null)
  187. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bufferManager");
  188. if (contentType == this.ContentType)
  189. contentType = null;
  190. if (TD.MtomMessageDecodingStartIsEnabled())
  191. {
  192. TD.MtomMessageDecodingStart();
  193. }
  194. MtomBufferedMessageData messageData = TakeBufferedReader();
  195. messageData.ContentType = contentType;
  196. messageData.Open(buffer, bufferManager);
  197. RecycledMessageState messageState = messageData.TakeMessageState();
  198. if (messageState == null)
  199. messageState = new RecycledMessageState();
  200. Message message = new BufferedMessage(messageData, messageState);
  201. message.Properties.Encoder = this;
  202. if (MessageLogger.LogMessagesAtTransportLevel)
  203. MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
  204. if (TD.MessageReadByEncoderIsEnabled() && buffer != null)
  205. {
  206. TD.MessageReadByEncoder(
  207. EventTraceActivityHelper.TryExtractActivity(message, true),
  208. buffer.Count,
  209. this);
  210. }
  211. return message;
  212. }
  213. public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
  214. {
  215. if (stream == null)
  216. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream"));
  217. if (contentType == this.ContentType)
  218. contentType = null;
  219. if (TD.MtomMessageDecodingStartIsEnabled())
  220. {
  221. TD.MtomMessageDecodingStart();
  222. }
  223. XmlReader reader = TakeStreamedReader(stream, contentType);
  224. Message message = Message.CreateMessage(reader, maxSizeOfHeaders, version);
  225. message.Properties.Encoder = this;
  226. if (TD.StreamedMessageReadByEncoderIsEnabled())
  227. {
  228. TD.StreamedMessageReadByEncoder(EventTraceActivityHelper.TryExtractActivity(message, true));
  229. }
  230. if (MessageLogger.LogMessagesAtTransportLevel)
  231. MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
  232. return message;
  233. }
  234. public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
  235. {
  236. return WriteMessage(message, maxMessageSize, bufferManager, messageOffset, GenerateStartInfoString(), null, null, true /*writeMessageHeaders*/);
  237. }
  238. internal string GetContentType(out string boundary)
  239. {
  240. string startInfo = GenerateStartInfoString();
  241. boundary = MimeBoundaryGenerator.Next();
  242. return FormatContentType(boundary, startInfo);
  243. }
  244. internal string FormatContentType(string boundary, string startInfo)
  245. {
  246. return String.Format(CultureInfo.InvariantCulture,
  247. "{0};start=\"<{1}>\";boundary=\"{2}\";start-info=\"{3}\"",
  248. mtomContentType, mtomStartUri, boundary, startInfo);
  249. }
  250. internal ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset, string boundary)
  251. {
  252. return WriteMessage(message, maxMessageSize, bufferManager, messageOffset, GenerateStartInfoString(), boundary, mtomStartUri, false /*writeMessageHeaders*/);
  253. }
  254. ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset, string startInfo, string boundary, string startUri, bool writeMessageHeaders)
  255. {
  256. if (message == null)
  257. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
  258. if (bufferManager == null)
  259. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bufferManager");
  260. if (maxMessageSize < 0)
  261. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxMessageSize", maxMessageSize,
  262. SR.GetString(SR.ValueMustBeNonNegative)));
  263. if (messageOffset < 0 || messageOffset > maxMessageSize)
  264. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("messageOffset", messageOffset,
  265. SR.GetString(SR.ValueMustBeInRange, 0, maxMessageSize)));
  266. ThrowIfMismatchedMessageVersion(message);
  267. EventTraceActivity eventTraceActivity = null;
  268. if (TD.MtomMessageEncodingStartIsEnabled())
  269. {
  270. eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
  271. TD.MtomMessageEncodingStart(eventTraceActivity);
  272. }
  273. message.Properties.Encoder = this;
  274. MtomBufferedMessageWriter messageWriter = TakeBufferedWriter();
  275. messageWriter.StartInfo = startInfo;
  276. messageWriter.Boundary = boundary;
  277. messageWriter.StartUri = startUri;
  278. messageWriter.WriteMessageHeaders = writeMessageHeaders;
  279. messageWriter.MaxSizeInBytes = maxMessageSize;
  280. ArraySegment<byte> messageData = messageWriter.WriteMessage(message, bufferManager, messageOffset, maxMessageSize);
  281. ReturnMessageWriter(messageWriter);
  282. if (TD.MessageWrittenByEncoderIsEnabled() && messageData != null)
  283. {
  284. TD.MessageWrittenByEncoder(
  285. eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message),
  286. messageData.Count,
  287. this);
  288. }
  289. if (MessageLogger.LogMessagesAtTransportLevel)
  290. {
  291. string contentType = null;
  292. if (boundary != null)
  293. contentType = FormatContentType(boundary, startInfo ?? GenerateStartInfoString());
  294. XmlDictionaryReader xmlDictionaryReader = XmlDictionaryReader.CreateMtomReader(messageData.Array, messageData.Offset, messageData.Count, MtomMessageEncoderFactory.GetSupportedEncodings(), contentType, XmlDictionaryReaderQuotas.Max, int.MaxValue, null);
  295. MessageLogger.LogMessage(ref message, xmlDictionaryReader, MessageLoggingSource.TransportSend);
  296. }
  297. return messageData;
  298. }
  299. public override void WriteMessage(Message message, Stream stream)
  300. {
  301. WriteMessage(message, stream, GenerateStartInfoString(), null, null, true /*writeMessageHeaders*/);
  302. }
  303. internal void WriteMessage(Message message, Stream stream, string boundary)
  304. {
  305. WriteMessage(message, stream, GenerateStartInfoString(), boundary, mtomStartUri, false /*writeMessageHeaders*/);
  306. }
  307. public override IAsyncResult BeginWriteMessage(Message message, Stream stream, AsyncCallback callback, object state)
  308. {
  309. return new WriteMessageAsyncResult(message, stream, this, callback, state);
  310. }
  311. internal IAsyncResult BeginWriteMessage(Message message, Stream stream, string boundary, AsyncCallback callback, object state)
  312. {
  313. return new WriteMessageAsyncResult(message, stream, boundary, this, callback, state);
  314. }
  315. public override void EndWriteMessage(IAsyncResult result)
  316. {
  317. WriteMessageAsyncResult.End(result);
  318. }
  319. void WriteMessage(Message message, Stream stream, string startInfo, string boundary, string startUri, bool writeMessageHeaders)
  320. {
  321. if (message == null)
  322. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
  323. if (stream == null)
  324. throw TraceUtility.ThrowHelperError(new ArgumentNullException("stream"), message);
  325. ThrowIfMismatchedMessageVersion(message);
  326. EventTraceActivity eventTraceActivity = null;
  327. if (TD.MtomMessageEncodingStartIsEnabled())
  328. {
  329. eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
  330. TD.MtomMessageEncodingStart(eventTraceActivity);
  331. }
  332. message.Properties.Encoder = this;
  333. if (MessageLogger.LogMessagesAtTransportLevel)
  334. MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
  335. XmlDictionaryWriter xmlWriter = TakeStreamedWriter(stream, startInfo, boundary, startUri, writeMessageHeaders);
  336. if (this.writeEncoding.WebName == "utf-8")
  337. {
  338. message.WriteMessage(xmlWriter);
  339. }
  340. else
  341. {
  342. xmlWriter.WriteStartDocument();
  343. message.WriteMessage(xmlWriter);
  344. xmlWriter.WriteEndDocument();
  345. }
  346. xmlWriter.Flush();
  347. ReturnStreamedWriter(xmlWriter);
  348. if (TD.StreamedMessageWrittenByEncoderIsEnabled())
  349. {
  350. TD.StreamedMessageWrittenByEncoder(eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message));
  351. }
  352. }
  353. XmlDictionaryWriter TakeStreamedWriter(Stream stream, string startInfo, string boundary, string startUri, bool writeMessageHeaders)
  354. {
  355. if (streamedWriterPool == null)
  356. {
  357. lock (thisLock)
  358. {
  359. if (streamedWriterPool == null)
  360. {
  361. streamedWriterPool = new SynchronizedPool<XmlDictionaryWriter>(maxWritePoolSize);
  362. }
  363. }
  364. }
  365. XmlDictionaryWriter xmlWriter = streamedWriterPool.Take();
  366. if (xmlWriter == null)
  367. {
  368. xmlWriter = XmlDictionaryWriter.CreateMtomWriter(stream, this.writeEncoding, int.MaxValue, startInfo, boundary, startUri, writeMessageHeaders, false);
  369. if (TD.WritePoolMissIsEnabled())
  370. {
  371. TD.WritePoolMiss(xmlWriter.GetType().Name);
  372. }
  373. }
  374. else
  375. {
  376. ((IXmlMtomWriterInitializer)xmlWriter).SetOutput(stream, this.writeEncoding, int.MaxValue, startInfo, boundary, startUri, writeMessageHeaders, false);
  377. }
  378. return xmlWriter;
  379. }
  380. void ReturnStreamedWriter(XmlDictionaryWriter xmlWriter)
  381. {
  382. xmlWriter.Close();
  383. streamedWriterPool.Return(xmlWriter);
  384. }
  385. MtomBufferedMessageWriter TakeBufferedWriter()
  386. {
  387. if (bufferedWriterPool == null)
  388. {
  389. lock (thisLock)
  390. {
  391. if (bufferedWriterPool == null)
  392. {
  393. bufferedWriterPool = new SynchronizedPool<MtomBufferedMessageWriter>(maxWritePoolSize);
  394. }
  395. }
  396. }
  397. MtomBufferedMessageWriter messageWriter = bufferedWriterPool.Take();
  398. if (messageWriter == null)
  399. {
  400. messageWriter = new MtomBufferedMessageWriter(this);
  401. if (TD.WritePoolMissIsEnabled())
  402. {
  403. TD.WritePoolMiss(messageWriter.GetType().Name);
  404. }
  405. }
  406. return messageWriter;
  407. }
  408. void ReturnMessageWriter(MtomBufferedMessageWriter messageWriter)
  409. {
  410. bufferedWriterPool.Return(messageWriter);
  411. }
  412. MtomBufferedMessageData TakeBufferedReader()
  413. {
  414. if (bufferedReaderPool == null)
  415. {
  416. lock (thisLock)
  417. {
  418. if (bufferedReaderPool == null)
  419. {
  420. bufferedReaderPool = new SynchronizedPool<MtomBufferedMessageData>(maxReadPoolSize);
  421. }
  422. }
  423. }
  424. MtomBufferedMessageData messageData = bufferedReaderPool.Take();
  425. if (messageData == null)
  426. {
  427. messageData = new MtomBufferedMessageData(this, maxPooledXmlReadersPerMessage);
  428. if (TD.ReadPoolMissIsEnabled())
  429. {
  430. TD.ReadPoolMiss(messageData.GetType().Name);
  431. }
  432. }
  433. return messageData;
  434. }
  435. void ReturnBufferedData(MtomBufferedMessageData messageData)
  436. {
  437. bufferedReaderPool.Return(messageData);
  438. }
  439. XmlReader TakeStreamedReader(Stream stream, string contentType)
  440. {
  441. if (streamedReaderPool == null)
  442. {
  443. lock (thisLock)
  444. {
  445. if (streamedReaderPool == null)
  446. {
  447. streamedReaderPool = new SynchronizedPool<XmlDictionaryReader>(maxReadPoolSize);
  448. }
  449. }
  450. }
  451. XmlDictionaryReader xmlReader = streamedReaderPool.Take();
  452. try
  453. {
  454. if (contentType == null || IsMTOMContentType(contentType))
  455. {
  456. if (xmlReader != null && xmlReader is IXmlMtomReaderInitializer)
  457. {
  458. ((IXmlMtomReaderInitializer)xmlReader).SetInput(stream, MtomMessageEncoderFactory.GetSupportedEncodings(), contentType, this.readerQuotas, this.maxBufferSize, onStreamedReaderClose);
  459. }
  460. else
  461. {
  462. xmlReader = XmlDictionaryReader.CreateMtomReader(stream, MtomMessageEncoderFactory.GetSupportedEncodings(), contentType, this.readerQuotas, this.maxBufferSize, onStreamedReaderClose);
  463. if (TD.ReadPoolMissIsEnabled())
  464. {
  465. TD.ReadPoolMiss(xmlReader.GetType().Name);
  466. }
  467. }
  468. }
  469. else
  470. {
  471. if (xmlReader != null && xmlReader is IXmlTextReaderInitializer)
  472. {
  473. ((IXmlTextReaderInitializer)xmlReader).SetInput(stream, TextMessageEncoderFactory.GetEncodingFromContentType(contentType, this.contentEncodingMap), this.readerQuotas, onStreamedReaderClose);
  474. }
  475. else
  476. {
  477. xmlReader = XmlDictionaryReader.CreateTextReader(stream, TextMessageEncoderFactory.GetEncodingFromContentType(contentType, this.contentEncodingMap), this.readerQuotas, onStreamedReaderClose);
  478. if (TD.ReadPoolMissIsEnabled())
  479. {
  480. TD.ReadPoolMiss(xmlReader.GetType().Name);
  481. }
  482. }
  483. }
  484. }
  485. catch (FormatException fe)
  486. {
  487. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
  488. SR.GetString(SR.SFxErrorCreatingMtomReader), fe));
  489. }
  490. catch (XmlException xe)
  491. {
  492. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
  493. SR.GetString(SR.SFxErrorCreatingMtomReader), xe));
  494. }
  495. return xmlReader;
  496. }
  497. void ReturnStreamedReader(XmlDictionaryReader xmlReader)
  498. {
  499. streamedReaderPool.Return(xmlReader);
  500. }
  501. SynchronizedPool<RecycledMessageState> RecycledStatePool
  502. {
  503. get
  504. {
  505. if (recycledStatePool == null)
  506. {
  507. lock (thisLock)
  508. {
  509. if (recycledStatePool == null)
  510. {
  511. recycledStatePool = new SynchronizedPool<RecycledMessageState>(maxReadPoolSize);
  512. }
  513. }
  514. }
  515. return recycledStatePool;
  516. }
  517. }
  518. string ITraceSourceStringProvider.GetSourceString()
  519. {
  520. return base.GetTraceSourceString();
  521. }
  522. class MtomBufferedMessageData : BufferedMessageData
  523. {
  524. MtomMessageEncoder messageEncoder;
  525. Pool<XmlDictionaryReader> readerPool;
  526. internal string ContentType;
  527. OnXmlDictionaryReaderClose onClose;
  528. public MtomBufferedMessageData(MtomMessageEncoder messageEncoder, int maxReaderPoolSize)
  529. : base(messageEncoder.RecycledStatePool)
  530. {
  531. this.messageEncoder = messageEncoder;
  532. readerPool = new Pool<XmlDictionaryReader>(maxReaderPoolSize);
  533. onClose = new OnXmlDictionaryReaderClose(OnXmlReaderClosed);
  534. }
  535. public override MessageEncoder MessageEncoder
  536. {
  537. get { return messageEncoder; }
  538. }
  539. public override XmlDictionaryReaderQuotas Quotas
  540. {
  541. get { return messageEncoder.bufferedReadReaderQuotas; }
  542. }
  543. protected override void OnClosed()
  544. {
  545. messageEncoder.ReturnBufferedData(this);
  546. }
  547. protected override XmlDictionaryReader TakeXmlReader()
  548. {
  549. try
  550. {
  551. ArraySegment<byte> buffer = this.Buffer;
  552. XmlDictionaryReader xmlReader = readerPool.Take();
  553. if (ContentType == null || messageEncoder.IsMTOMContentType(ContentType))
  554. {
  555. if (xmlReader != null && xmlReader is IXmlMtomReaderInitializer)
  556. {
  557. ((IXmlMtomReaderInitializer)xmlReader).SetInput(buffer.Array, buffer.Offset, buffer.Count, MtomMessageEncoderFactory.GetSupportedEncodings(), ContentType, this.Quotas, this.messageEncoder.MaxBufferSize, onClose);
  558. }
  559. else
  560. {
  561. xmlReader = XmlDictionaryReader.CreateMtomReader(buffer.Array, buffer.Offset, buffer.Count, MtomMessageEncoderFactory.GetSupportedEncodings(), ContentType, this.Quotas, this.messageEncoder.MaxBufferSize, onClose);
  562. if (TD.ReadPoolMissIsEnabled())
  563. {
  564. TD.ReadPoolMiss(xmlReader.GetType().Name);
  565. }
  566. }
  567. }
  568. else
  569. {
  570. if (xmlReader != null && xmlReader is IXmlTextReaderInitializer)
  571. {
  572. ((IXmlTextReaderInitializer)xmlReader).SetInput(buffer.Array, buffer.Offset, buffer.Count, TextMessageEncoderFactory.GetEncodingFromContentType(ContentType, this.messageEncoder.contentEncodingMap), this.Quotas, onClose);
  573. }
  574. else
  575. {
  576. xmlReader = XmlDictionaryReader.CreateTextReader(buffer.Array, buffer.Offset, buffer.Count, TextMessageEncoderFactory.GetEncodingFromContentType(ContentType, this.messageEncoder.contentEncodingMap), this.Quotas, onClose);
  577. if (TD.ReadPoolMissIsEnabled())
  578. {
  579. TD.ReadPoolMiss(xmlReader.GetType().Name);
  580. }
  581. }
  582. }
  583. return xmlReader;
  584. }
  585. catch (FormatException fe)
  586. {
  587. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
  588. SR.GetString(SR.SFxErrorCreatingMtomReader), fe));
  589. }
  590. catch (XmlException xe)
  591. {
  592. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
  593. SR.GetString(SR.SFxErrorCreatingMtomReader), xe));
  594. }
  595. }
  596. protected override void ReturnXmlReader(XmlDictionaryReader xmlReader)
  597. {
  598. if (xmlReader != null)
  599. readerPool.Return(xmlReader);
  600. }
  601. }
  602. class MtomBufferedMessageWriter : BufferedMessageWriter
  603. {
  604. MtomMessageEncoder messageEncoder;
  605. internal bool WriteMessageHeaders;
  606. internal string StartInfo;
  607. internal string StartUri;
  608. internal string Boundary;
  609. internal int MaxSizeInBytes = int.MaxValue;
  610. XmlDictionaryWriter writer;
  611. public MtomBufferedMessageWriter(MtomMessageEncoder messageEncoder)
  612. {
  613. this.messageEncoder = messageEncoder;
  614. }
  615. protected override XmlDictionaryWriter TakeXmlWriter(Stream stream)
  616. {
  617. XmlDictionaryWriter returnedWriter = writer;
  618. if (returnedWriter == null)
  619. {
  620. returnedWriter = XmlDictionaryWriter.CreateMtomWriter(stream, messageEncoder.writeEncoding, MaxSizeInBytes, StartInfo, Boundary, StartUri, WriteMessageHeaders, false);
  621. }
  622. else
  623. {
  624. writer = null;
  625. ((IXmlMtomWriterInitializer)returnedWriter).SetOutput(stream, messageEncoder.writeEncoding, MaxSizeInBytes, StartInfo, Boundary, StartUri, WriteMessageHeaders, false);
  626. }
  627. if (messageEncoder.writeEncoding.WebName != "utf-8")
  628. returnedWriter.WriteStartDocument();
  629. return returnedWriter;
  630. }
  631. protected override void ReturnXmlWriter(XmlDictionaryWriter writer)
  632. {
  633. writer.Close();
  634. if (this.writer == null)
  635. this.writer = writer;
  636. }
  637. }
  638. class WriteMessageAsyncResult : ScheduleActionItemAsyncResult
  639. {
  640. string boundary;
  641. MtomMessageEncoder encoder;
  642. Message message;
  643. Stream stream;
  644. bool writeBoundary;
  645. public WriteMessageAsyncResult(Message message, Stream stream, MtomMessageEncoder encoder, AsyncCallback callback, object state)
  646. : base(callback, state)
  647. {
  648. Fx.Assert(encoder != null, "encoder should never be null");
  649. this.encoder = encoder;
  650. this.message = message;
  651. this.stream = stream;
  652. Schedule();
  653. }
  654. public WriteMessageAsyncResult(Message message, Stream stream, string boundary, MtomMessageEncoder encoder, AsyncCallback callback, object state)
  655. : base(callback, state)
  656. {
  657. Fx.Assert(encoder != null, "encoder should never be null");
  658. this.encoder = encoder;
  659. this.message = message;
  660. this.stream = stream;
  661. this.boundary = boundary;
  662. this.writeBoundary = true;
  663. Schedule();
  664. }
  665. protected override void OnDoWork()
  666. {
  667. this.encoder.WriteMessage(this.message, this.stream, this.encoder.GenerateStartInfoString(), string.IsNullOrEmpty(this.boundary) ? null : this.boundary, this.writeBoundary ? MtomMessageEncoder.mtomStartUri : null, !this.writeBoundary /*writeMessageHeaders*/);
  668. }
  669. }
  670. }
  671. }