| File: System\ServiceModel\Channels\BufferedMessageWriter.cs | Web Access |
| Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.IO; using System.Xml; namespace System.ServiceModel.Channels { internal abstract class BufferedMessageWriter { private int[] _sizeHistory; private int _sizeHistoryIndex; private const int sizeHistoryCount = 4; private const int expectedSizeVariance = 256; private BufferManagerOutputStream _stream; public BufferedMessageWriter() { _stream = new BufferManagerOutputStream(SRP.MaxSentMessageSizeExceeded); InitMessagePredicter(); } protected abstract XmlDictionaryWriter TakeXmlWriter(Stream stream); protected abstract void ReturnXmlWriter(XmlDictionaryWriter writer); public ArraySegment<byte> WriteMessage(Message message, BufferManager bufferManager, int initialOffset, int maxSizeQuota) { int effectiveMaxSize; // make sure that maxSize has room for initialOffset without overflowing, since // the effective buffer size is message size + initialOffset if (maxSizeQuota <= int.MaxValue - initialOffset) { effectiveMaxSize = maxSizeQuota + initialOffset; } else { effectiveMaxSize = int.MaxValue; } int predictedMessageSize = PredictMessageSize(); if (predictedMessageSize > effectiveMaxSize) { predictedMessageSize = effectiveMaxSize; } else if (predictedMessageSize < initialOffset) { predictedMessageSize = initialOffset; } try { _stream.Init(predictedMessageSize, maxSizeQuota, effectiveMaxSize, bufferManager); _stream.Skip(initialOffset); XmlDictionaryWriter writer = TakeXmlWriter(_stream); OnWriteStartMessage(writer); message.WriteMessage(writer); OnWriteEndMessage(writer); writer.Flush(); ReturnXmlWriter(writer); int size; byte[] buffer = _stream.ToArray(out size); RecordActualMessageSize(size); return new ArraySegment<byte>(buffer, initialOffset, size - initialOffset); } finally { _stream.Clear(); } } protected virtual void OnWriteStartMessage(XmlDictionaryWriter writer) { } protected virtual void OnWriteEndMessage(XmlDictionaryWriter writer) { } private void InitMessagePredicter() { _sizeHistory = new int[4]; for (int i = 0; i < sizeHistoryCount; i++) { _sizeHistory[i] = 256; } } private int PredictMessageSize() { int max = 0; for (int i = 0; i < sizeHistoryCount; i++) { if (_sizeHistory[i] > max) { max = _sizeHistory[i]; } } return max + expectedSizeVariance; } private void RecordActualMessageSize(int size) { _sizeHistory[_sizeHistoryIndex] = size; _sizeHistoryIndex = (_sizeHistoryIndex + 1) % sizeHistoryCount; } } }