|
//------------------------------------------------------------
// 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;
}
}
}
}
}
}
|