| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Channels
- {
- using System.Globalization;
- using System.IO;
- using System.Net.Mime;
- using System.Runtime;
- using System.Runtime.Diagnostics;
- using System.ServiceModel.Diagnostics;
- using System.ServiceModel.Diagnostics.Application;
- using System.Text;
- using System.Xml;
- class TextMessageEncoderFactory : MessageEncoderFactory
- {
- TextMessageEncoder messageEncoder;
- internal static ContentEncoding[] Soap11Content = GetContentEncodingMap(MessageVersion.Soap11WSAddressing10);
- internal static ContentEncoding[] Soap12Content = GetContentEncodingMap(MessageVersion.Soap12WSAddressing10);
- internal static ContentEncoding[] SoapNoneContent = GetContentEncodingMap(MessageVersion.None);
- internal const string Soap11MediaType = "text/xml";
- internal const string Soap12MediaType = "application/soap+xml";
- const string XmlMediaType = "application/xml";
- public TextMessageEncoderFactory(MessageVersion version, Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, XmlDictionaryReaderQuotas quotas)
- {
- messageEncoder = new TextMessageEncoder(version, writeEncoding, maxReadPoolSize, maxWritePoolSize, quotas);
- }
- public override MessageEncoder Encoder
- {
- get { return messageEncoder; }
- }
- public override MessageVersion MessageVersion
- {
- get { return messageEncoder.MessageVersion; }
- }
- public int MaxWritePoolSize
- {
- get { return messageEncoder.MaxWritePoolSize; }
- }
- public int MaxReadPoolSize
- {
- get { return messageEncoder.MaxReadPoolSize; }
- }
- public static Encoding[] GetSupportedEncodings()
- {
- Encoding[] supported = TextEncoderDefaults.SupportedEncodings;
- Encoding[] enc = new Encoding[supported.Length];
- Array.Copy(supported, enc, supported.Length);
- return enc;
- }
- public XmlDictionaryReaderQuotas ReaderQuotas
- {
- get
- {
- return messageEncoder.ReaderQuotas;
- }
- }
- internal static string GetMediaType(MessageVersion version)
- {
- string mediaType = null;
- if (version.Envelope == EnvelopeVersion.Soap12)
- {
- mediaType = TextMessageEncoderFactory.Soap12MediaType;
- }
- else if (version.Envelope == EnvelopeVersion.Soap11)
- {
- mediaType = TextMessageEncoderFactory.Soap11MediaType;
- }
- else if (version.Envelope == EnvelopeVersion.None)
- {
- mediaType = TextMessageEncoderFactory.XmlMediaType;
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.EnvelopeVersionNotSupported, version.Envelope)));
- }
- return mediaType;
- }
- internal static string GetContentType(string mediaType, Encoding encoding)
- {
- return String.Format(CultureInfo.InvariantCulture, "{0}; charset={1}", mediaType, TextEncoderDefaults.EncodingToCharSet(encoding));
- }
- static ContentEncoding[] GetContentEncodingMap(MessageVersion version)
- {
- Encoding[] readEncodings = TextMessageEncoderFactory.GetSupportedEncodings();
- string media = GetMediaType(version);
- ContentEncoding[] map = new ContentEncoding[readEncodings.Length];
- for (int i = 0; i < readEncodings.Length; i++)
- {
- ContentEncoding contentEncoding = new ContentEncoding();
- contentEncoding.contentType = GetContentType(media, readEncodings[i]);
- contentEncoding.encoding = readEncodings[i];
- map[i] = contentEncoding;
- }
- return map;
- }
- internal static Encoding GetEncodingFromContentType(string contentType, ContentEncoding[] contentMap)
- {
- if (contentType == null)
- {
- return null;
- }
- // Check for known/expected content types
- for (int i = 0; i < contentMap.Length; i++)
- {
- if (contentMap[i].contentType == contentType)
- {
- return contentMap[i].encoding;
- }
- }
- // then some heuristic matches (since System.Mime.ContentType is a performance hit)
- // start by looking for a parameter.
- // If none exists, we don't have an encoding
- int semiColonIndex = contentType.IndexOf(';');
- if (semiColonIndex == -1)
- {
- return null;
- }
- // optimize for charset being the first parameter
- int charsetValueIndex = -1;
- // for Indigo scenarios, we'll have "; charset=", so check for the c
- if ((contentType.Length > semiColonIndex + 11) // need room for parameter + charset + '='
- && contentType[semiColonIndex + 2] == 'c'
- && string.Compare("charset=", 0, contentType, semiColonIndex + 2, 8, StringComparison.OrdinalIgnoreCase) == 0)
- {
- charsetValueIndex = semiColonIndex + 10;
- }
- else
- {
- // look for charset= somewhere else in the message
- int paramIndex = contentType.IndexOf("charset=", semiColonIndex + 1, StringComparison.OrdinalIgnoreCase);
- if (paramIndex != -1)
- {
- // validate there's only whitespace or semi-colons beforehand
- for (int i = paramIndex - 1; i >= semiColonIndex; i--)
- {
- if (contentType[i] == ';')
- {
- charsetValueIndex = paramIndex + 8;
- break;
- }
- if (contentType[i] == '\n')
- {
- if (i == semiColonIndex || contentType[i - 1] != '\r')
- {
- break;
- }
- i--;
- continue;
- }
- if (contentType[i] != ' '
- && contentType[i] != '\t')
- {
- break;
- }
- }
- }
- }
- string charSet;
- Encoding enc;
- // we have a possible charset value. If it's easy to parse, do so
- if (charsetValueIndex != -1)
- {
- // get the next semicolon
- semiColonIndex = contentType.IndexOf(';', charsetValueIndex);
- if (semiColonIndex == -1)
- {
- charSet = contentType.Substring(charsetValueIndex);
- }
- else
- {
- charSet = contentType.Substring(charsetValueIndex, semiColonIndex - charsetValueIndex);
- }
- // and some minimal quote stripping
- if (charSet.Length > 2 && charSet[0] == '"' && charSet[charSet.Length - 1] == '"')
- {
- charSet = charSet.Substring(1, charSet.Length - 2);
- }
- Fx.Assert(charSet == (new ContentType(contentType)).CharSet,
- "CharSet parsing failed to correctly parse the ContentType header.");
- if (TryGetEncodingFromCharSet(charSet, out enc))
- {
- return enc;
- }
- }
- // our quick heuristics failed. fall back to System.Net
- try
- {
- ContentType parsedContentType = new ContentType(contentType);
- charSet = parsedContentType.CharSet;
- }
- catch (FormatException e)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.EncoderBadContentType), e));
- }
- if (TryGetEncodingFromCharSet(charSet, out enc))
- return enc;
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.EncoderUnrecognizedCharSet, charSet)));
- }
- internal static bool TryGetEncodingFromCharSet(string charSet, out Encoding encoding)
- {
- encoding = null;
- if (charSet == null || charSet.Length == 0)
- return true;
- return TextEncoderDefaults.TryGetEncoding(charSet, out encoding);
- }
- internal class ContentEncoding
- {
- internal string contentType;
- internal Encoding encoding;
- }
- class TextMessageEncoder : MessageEncoder, ITraceSourceStringProvider
- {
- int maxReadPoolSize;
- int maxWritePoolSize;
- // Double-checked locking pattern requires volatile for read/write synchronization
- volatile SynchronizedPool<XmlDictionaryWriter> streamedWriterPool;
- volatile SynchronizedPool<XmlDictionaryReader> streamedReaderPool;
- volatile SynchronizedPool<UTF8BufferedMessageData> bufferedReaderPool;
- volatile SynchronizedPool<TextBufferedMessageWriter> bufferedWriterPool;
- volatile SynchronizedPool<RecycledMessageState> recycledStatePool;
- object thisLock;
- string contentType;
- string mediaType;
- Encoding writeEncoding;
- MessageVersion version;
- bool optimizeWriteForUTF8;
- const int maxPooledXmlReadersPerMessage = 2;
- XmlDictionaryReaderQuotas readerQuotas;
- XmlDictionaryReaderQuotas bufferedReadReaderQuotas;
- OnXmlDictionaryReaderClose onStreamedReaderClose;
- ContentEncoding[] contentEncodingMap;
- public TextMessageEncoder(MessageVersion version, Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, XmlDictionaryReaderQuotas quotas)
- {
- if (version == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
- if (writeEncoding == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writeEncoding");
- TextEncoderDefaults.ValidateEncoding(writeEncoding);
- this.writeEncoding = writeEncoding;
- optimizeWriteForUTF8 = IsUTF8Encoding(writeEncoding);
- thisLock = new object();
- this.version = version;
- this.maxReadPoolSize = maxReadPoolSize;
- this.maxWritePoolSize = maxWritePoolSize;
- this.readerQuotas = new XmlDictionaryReaderQuotas();
- quotas.CopyTo(this.readerQuotas);
- this.bufferedReadReaderQuotas = EncoderHelpers.GetBufferedReadQuotas(this.readerQuotas);
- this.onStreamedReaderClose = new OnXmlDictionaryReaderClose(ReturnStreamedReader);
- this.mediaType = TextMessageEncoderFactory.GetMediaType(version);
- this.contentType = TextMessageEncoderFactory.GetContentType(mediaType, writeEncoding);
- if (version.Envelope == EnvelopeVersion.Soap12)
- {
- contentEncodingMap = TextMessageEncoderFactory.Soap12Content;
- }
- else if (version.Envelope == EnvelopeVersion.Soap11)
- {
- contentEncodingMap = TextMessageEncoderFactory.Soap11Content;
- }
- else if (version.Envelope == EnvelopeVersion.None)
- {
- contentEncodingMap = TextMessageEncoderFactory.SoapNoneContent;
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
- SR.GetString(SR.EnvelopeVersionNotSupported, version.Envelope)));
- }
- }
- static bool IsUTF8Encoding(Encoding encoding)
- {
- return encoding.WebName == "utf-8";
- }
- public override string ContentType
- {
- get { return contentType; }
- }
- public int MaxWritePoolSize
- {
- get { return maxWritePoolSize; }
- }
- public int MaxReadPoolSize
- {
- get { return maxReadPoolSize; }
- }
- public XmlDictionaryReaderQuotas ReaderQuotas
- {
- get
- {
- return readerQuotas;
- }
- }
- public override string MediaType
- {
- get { return mediaType; }
- }
- public override MessageVersion MessageVersion
- {
- get { return version; }
- }
- object ThisLock
- {
- get { return thisLock; }
- }
- internal override bool IsCharSetSupported(string charSet)
- {
- Encoding tmp;
- return TextEncoderDefaults.TryGetEncoding(charSet, out tmp);
- }
- public override bool IsContentTypeSupported(string contentType)
- {
- if (contentType == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
- }
- if (base.IsContentTypeSupported(contentType))
- {
- return true;
- }
- // we support a few extra content types for "none"
- if (MessageVersion == MessageVersion.None)
- {
- const string rss1MediaType = "text/xml";
- const string rss2MediaType = "application/rss+xml";
- const string atomMediaType = "application/atom+xml";
- const string htmlMediaType = "text/html";
- if (IsContentTypeSupported(contentType, rss1MediaType, rss1MediaType))
- {
- return true;
- }
- if (IsContentTypeSupported(contentType, rss2MediaType, rss2MediaType))
- {
- return true;
- }
- if (IsContentTypeSupported(contentType, htmlMediaType, atomMediaType))
- {
- return true;
- }
- if (IsContentTypeSupported(contentType, atomMediaType, atomMediaType))
- {
- return true;
- }
- // application/xml checked by base method
- }
- return false;
- }
- public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
- {
- if (bufferManager == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("bufferManager"));
- if (TD.TextMessageDecodingStartIsEnabled())
- {
- TD.TextMessageDecodingStart();
- }
- Message message;
- UTF8BufferedMessageData messageData = TakeBufferedReader();
- messageData.Encoding = GetEncodingFromContentType(contentType, this.contentEncodingMap);
- messageData.Open(buffer, bufferManager);
- RecycledMessageState messageState = messageData.TakeMessageState();
- if (messageState == null)
- messageState = new RecycledMessageState();
- message = new BufferedMessage(messageData, messageState);
- message.Properties.Encoder = this;
- if (TD.MessageReadByEncoderIsEnabled() && buffer != null)
- {
- TD.MessageReadByEncoder(
- EventTraceActivityHelper.TryExtractActivity(message, true),
- buffer.Count,
- this);
- }
- if (MessageLogger.LogMessagesAtTransportLevel)
- MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
- return message;
- }
- public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
- {
- if (stream == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream"));
- if (TD.TextMessageDecodingStartIsEnabled())
- {
- TD.TextMessageDecodingStart();
- }
- XmlReader reader = TakeStreamedReader(stream, GetEncodingFromContentType(contentType, this.contentEncodingMap));
- Message message = Message.CreateMessage(reader, maxSizeOfHeaders, version);
- message.Properties.Encoder = this;
- if (TD.StreamedMessageReadByEncoderIsEnabled())
- {
- TD.StreamedMessageReadByEncoder(EventTraceActivityHelper.TryExtractActivity(message, true));
- }
- if (MessageLogger.LogMessagesAtTransportLevel)
- MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
- return message;
- }
- public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
- {
- if (message == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
- if (bufferManager == null)
- throw TraceUtility.ThrowHelperError(new ArgumentNullException("bufferManager"), message);
- if (maxMessageSize < 0)
- throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxMessageSize", maxMessageSize,
- SR.GetString(SR.ValueMustBeNonNegative)), message);
- if (messageOffset < 0 || messageOffset > maxMessageSize)
- throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException("messageOffset", messageOffset,
- SR.GetString(SR.ValueMustBeInRange, 0, maxMessageSize)), message);
- ThrowIfMismatchedMessageVersion(message);
- EventTraceActivity eventTraceActivity = null;
- if (TD.TextMessageEncodingStartIsEnabled())
- {
- eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
- TD.TextMessageEncodingStart(eventTraceActivity);
- }
- message.Properties.Encoder = this;
- TextBufferedMessageWriter messageWriter = TakeBufferedWriter();
- ArraySegment<byte> messageData = messageWriter.WriteMessage(message, bufferManager, messageOffset, maxMessageSize);
- ReturnMessageWriter(messageWriter);
- if (TD.MessageWrittenByEncoderIsEnabled() && messageData != null)
- {
- TD.MessageWrittenByEncoder(
- eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message),
- messageData.Count,
- this);
- }
- if (MessageLogger.LogMessagesAtTransportLevel)
- {
- XmlDictionaryReader xmlDictionaryReader = XmlDictionaryReader.CreateTextReader(messageData.Array, messageData.Offset, messageData.Count, null, XmlDictionaryReaderQuotas.Max, null);
- MessageLogger.LogMessage(ref message, xmlDictionaryReader, MessageLoggingSource.TransportSend);
- }
- return messageData;
- }
- public override void WriteMessage(Message message, Stream stream)
- {
- if (message == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
- if (stream == null)
- throw TraceUtility.ThrowHelperError(new ArgumentNullException("stream"), message);
- ThrowIfMismatchedMessageVersion(message);
- EventTraceActivity eventTraceActivity = null;
- if (TD.TextMessageEncodingStartIsEnabled())
- {
- eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
- TD.TextMessageEncodingStart(eventTraceActivity);
- }
- message.Properties.Encoder = this;
- XmlDictionaryWriter xmlWriter = TakeStreamedWriter(stream);
- if (optimizeWriteForUTF8)
- {
- message.WriteMessage(xmlWriter);
- }
- else
- {
- xmlWriter.WriteStartDocument();
- message.WriteMessage(xmlWriter);
- xmlWriter.WriteEndDocument();
- }
- xmlWriter.Flush();
- ReturnStreamedWriter(xmlWriter);
- if (TD.StreamedMessageWrittenByEncoderIsEnabled())
- {
- TD.StreamedMessageWrittenByEncoder(eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message));
- }
- if (MessageLogger.LogMessagesAtTransportLevel)
- MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
- }
- public override IAsyncResult BeginWriteMessage(Message message, Stream stream, AsyncCallback callback, object state)
- {
- if (message == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("message"));
- if (stream == null)
- throw TraceUtility.ThrowHelperError(new ArgumentNullException("stream"), message);
- ThrowIfMismatchedMessageVersion(message);
- message.Properties.Encoder = this;
- return new WriteMessageAsyncResult(message, stream, this, callback, state);
- }
- public override void EndWriteMessage(IAsyncResult result)
- {
- WriteMessageAsyncResult.End(result);
- }
- class WriteMessageAsyncResult : AsyncResult
- {
- static AsyncCompletion onWriteMessage = new AsyncCompletion(OnWriteMessage);
- Message message;
- TextMessageEncoder textEncoder;
- XmlDictionaryWriter xmlWriter;
- EventTraceActivity eventTraceActivity;
- public WriteMessageAsyncResult(Message message, Stream stream, TextMessageEncoder textEncoder, AsyncCallback callback, object state)
- : base(callback, state)
- {
- this.message = message;
- this.textEncoder = textEncoder;
- this.xmlWriter = textEncoder.TakeStreamedWriter(stream);
- this.eventTraceActivity = null;
- if (TD.TextMessageEncodingStartIsEnabled())
- {
- this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
- TD.TextMessageEncodingStart(this.eventTraceActivity);
- }
- if (!textEncoder.optimizeWriteForUTF8)
- {
- xmlWriter.WriteStartDocument();
- }
- IAsyncResult result = message.BeginWriteMessage(this.xmlWriter, PrepareAsyncCompletion(onWriteMessage), this);
- if (SyncContinue(result))
- {
- this.Complete(true);
- }
- }
- static bool OnWriteMessage(IAsyncResult result)
- {
- WriteMessageAsyncResult thisPtr = (WriteMessageAsyncResult)result.AsyncState;
- return thisPtr.HandleWriteMessage(result);
- }
- bool HandleWriteMessage(IAsyncResult result)
- {
- message.EndWriteMessage(result);
- if (!textEncoder.optimizeWriteForUTF8)
- {
- this.xmlWriter.WriteEndDocument();
- }
- xmlWriter.Flush(); // blocking call
- textEncoder.ReturnStreamedWriter(this.xmlWriter);
- if (TD.MessageWrittenAsynchronouslyByEncoderIsEnabled())
- {
- TD.MessageWrittenAsynchronouslyByEncoder(
- this.eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message));
- }
- if (MessageLogger.LogMessagesAtTransportLevel)
- MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
- return true;
- }
- public static void End(IAsyncResult result)
- {
- AsyncResult.End<WriteMessageAsyncResult>(result);
- }
- }
- XmlDictionaryWriter TakeStreamedWriter(Stream stream)
- {
- if (streamedWriterPool == null)
- {
- lock (ThisLock)
- {
- if (streamedWriterPool == null)
- {
- streamedWriterPool = new SynchronizedPool<XmlDictionaryWriter>(maxWritePoolSize);
- }
- }
- }
- XmlDictionaryWriter xmlWriter = streamedWriterPool.Take();
- if (xmlWriter == null)
- {
- xmlWriter = XmlDictionaryWriter.CreateTextWriter(stream, this.writeEncoding, false);
- if (TD.WritePoolMissIsEnabled())
- {
- TD.WritePoolMiss(xmlWriter.GetType().Name);
- }
- }
- else
- {
- ((IXmlTextWriterInitializer)xmlWriter).SetOutput(stream, this.writeEncoding, false);
- }
- return xmlWriter;
- }
- void ReturnStreamedWriter(XmlWriter xmlWriter)
- {
- xmlWriter.Close();
- streamedWriterPool.Return((XmlDictionaryWriter)xmlWriter);
- }
- TextBufferedMessageWriter TakeBufferedWriter()
- {
- if (bufferedWriterPool == null)
- {
- lock (ThisLock)
- {
- if (bufferedWriterPool == null)
- {
- bufferedWriterPool = new SynchronizedPool<TextBufferedMessageWriter>(maxWritePoolSize);
- }
- }
- }
- TextBufferedMessageWriter messageWriter = bufferedWriterPool.Take();
- if (messageWriter == null)
- {
- messageWriter = new TextBufferedMessageWriter(this);
- if (TD.WritePoolMissIsEnabled())
- {
- TD.WritePoolMiss(messageWriter.GetType().Name);
- }
- }
- return messageWriter;
- }
- void ReturnMessageWriter(TextBufferedMessageWriter messageWriter)
- {
- bufferedWriterPool.Return(messageWriter);
- }
- XmlReader TakeStreamedReader(Stream stream, Encoding enc)
- {
- if (streamedReaderPool == null)
- {
- lock (ThisLock)
- {
- if (streamedReaderPool == null)
- {
- streamedReaderPool = new SynchronizedPool<XmlDictionaryReader>(maxReadPoolSize);
- }
- }
- }
- XmlDictionaryReader xmlReader = streamedReaderPool.Take();
- if (xmlReader == null)
- {
- xmlReader = XmlDictionaryReader.CreateTextReader(stream, enc, this.readerQuotas, null);
- if (TD.ReadPoolMissIsEnabled())
- {
- TD.ReadPoolMiss(xmlReader.GetType().Name);
- }
- }
- else
- {
- ((IXmlTextReaderInitializer)xmlReader).SetInput(stream, enc, this.readerQuotas, onStreamedReaderClose);
- }
- return xmlReader;
- }
- void ReturnStreamedReader(XmlDictionaryReader xmlReader)
- {
- streamedReaderPool.Return(xmlReader);
- }
- XmlDictionaryWriter CreateWriter(Stream stream)
- {
- return XmlDictionaryWriter.CreateTextWriter(stream, writeEncoding, false);
- }
- UTF8BufferedMessageData TakeBufferedReader()
- {
- if (bufferedReaderPool == null)
- {
- lock (ThisLock)
- {
- if (bufferedReaderPool == null)
- {
- bufferedReaderPool = new SynchronizedPool<UTF8BufferedMessageData>(maxReadPoolSize);
- }
- }
- }
- UTF8BufferedMessageData messageData = bufferedReaderPool.Take();
- if (messageData == null)
- {
- messageData = new UTF8BufferedMessageData(this, maxPooledXmlReadersPerMessage);
- if (TD.ReadPoolMissIsEnabled())
- {
- TD.ReadPoolMiss(messageData.GetType().Name);
- }
- }
- return messageData;
- }
- void ReturnBufferedData(UTF8BufferedMessageData messageData)
- {
- bufferedReaderPool.Return(messageData);
- }
- SynchronizedPool<RecycledMessageState> RecycledStatePool
- {
- get
- {
- if (recycledStatePool == null)
- {
- lock (ThisLock)
- {
- if (recycledStatePool == null)
- {
- recycledStatePool = new SynchronizedPool<RecycledMessageState>(maxReadPoolSize);
- }
- }
- }
- return recycledStatePool;
- }
- }
- string ITraceSourceStringProvider.GetSourceString()
- {
- return base.GetTraceSourceString();
- }
- static readonly byte[] xmlDeclarationStartText = { (byte)'<', (byte)'?', (byte)'x', (byte)'m', (byte)'l' };
- static readonly byte[] version10Text = { (byte)'v', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n', (byte)'=', (byte)'"', (byte)'1', (byte)'.', (byte)'0', (byte)'"' };
- static readonly byte[] encodingText = { (byte)'e', (byte)'n', (byte)'c', (byte)'o', (byte)'d', (byte)'i', (byte)'n', (byte)'g', (byte)'=' };
- class UTF8BufferedMessageData : BufferedMessageData
- {
- TextMessageEncoder messageEncoder;
- Pool<XmlDictionaryReader> readerPool;
- OnXmlDictionaryReaderClose onClose;
- Encoding encoding;
- const int additionalNodeSpace = 1024;
- public UTF8BufferedMessageData(TextMessageEncoder messageEncoder, int maxReaderPoolSize)
- : base(messageEncoder.RecycledStatePool)
- {
- this.messageEncoder = messageEncoder;
- readerPool = new Pool<XmlDictionaryReader>(maxReaderPoolSize);
- onClose = new OnXmlDictionaryReaderClose(OnXmlReaderClosed);
- }
- internal Encoding Encoding
- {
- set
- {
- this.encoding = value;
- }
- }
- public override MessageEncoder MessageEncoder
- {
- get { return messageEncoder; }
- }
- public override XmlDictionaryReaderQuotas Quotas
- {
- get { return messageEncoder.bufferedReadReaderQuotas; }
- }
- protected override void OnClosed()
- {
- messageEncoder.ReturnBufferedData(this);
- }
- protected override XmlDictionaryReader TakeXmlReader()
- {
- ArraySegment<byte> buffer = this.Buffer;
- XmlDictionaryReader xmlReader = readerPool.Take();
- if (xmlReader == null)
- {
- xmlReader = XmlDictionaryReader.CreateTextReader(buffer.Array, buffer.Offset, buffer.Count, this.encoding, this.Quotas, onClose);
- if (TD.ReadPoolMissIsEnabled())
- {
- TD.ReadPoolMiss(xmlReader.GetType().Name);
- }
- }
- else
- {
- ((IXmlTextReaderInitializer)xmlReader).SetInput(buffer.Array, buffer.Offset, buffer.Count, this.encoding, this.Quotas, onClose);
- }
- return xmlReader;
- }
- protected override void ReturnXmlReader(XmlDictionaryReader xmlReader)
- {
- if (xmlReader != null)
- {
- readerPool.Return(xmlReader);
- }
- }
- }
- class TextBufferedMessageWriter : BufferedMessageWriter
- {
- TextMessageEncoder messageEncoder;
- XmlDictionaryWriter writer;
- public TextBufferedMessageWriter(TextMessageEncoder messageEncoder)
- {
- this.messageEncoder = messageEncoder;
- }
- protected override void OnWriteStartMessage(XmlDictionaryWriter writer)
- {
- if (!messageEncoder.optimizeWriteForUTF8)
- writer.WriteStartDocument();
- }
- protected override void OnWriteEndMessage(XmlDictionaryWriter writer)
- {
- if (!messageEncoder.optimizeWriteForUTF8)
- writer.WriteEndDocument();
- }
- protected override XmlDictionaryWriter TakeXmlWriter(Stream stream)
- {
- if (messageEncoder.optimizeWriteForUTF8)
- {
- XmlDictionaryWriter returnedWriter = writer;
- if (returnedWriter == null)
- {
- returnedWriter = XmlDictionaryWriter.CreateTextWriter(stream, messageEncoder.writeEncoding, false);
- }
- else
- {
- writer = null;
- ((IXmlTextWriterInitializer)returnedWriter).SetOutput(stream, messageEncoder.writeEncoding, false);
- }
- return returnedWriter;
- }
- else
- {
- return messageEncoder.CreateWriter(stream);
- }
- }
- protected override void ReturnXmlWriter(XmlDictionaryWriter writer)
- {
- writer.Close();
- if (messageEncoder.optimizeWriteForUTF8)
- {
- if (this.writer == null)
- this.writer = writer;
- }
- }
- }
- }
- }
- }
|