HttpWriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / xsp / System / Web / HttpWriter.cs / 2 / HttpWriter.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 * Response Writer and Stream implementation 
 *
 * Copyright (c) 1998 Microsoft Corporation 
 */

namespace System.Web {
    using System.Collections; 
    using System.Globalization;
    using System.IO; 
    using System.Runtime.Serialization.Formatters; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading;
    using System.Web.Util;
    using System.Web.Hosting;
 
    using IIS = System.Web.Hosting.UnsafeIISMethods;
 
    // 
    //  HttpWriter buffer recycling support
    // 

    /*
     * Constants for buffering
     */ 
    internal static class BufferingParams {
        internal static readonly int INTEGRATED_MODE_BUFFER_SIZE;   // native buffer size for integrated mode 
        internal const int OUTPUT_BUFFER_SIZE         = 31*1024;    // output is a chain of this size buffers 
        internal const int MAX_FREE_BYTES_TO_CACHE    = 4096;       // don't compress when taking snapshot if free bytes < this
        internal const int MAX_FREE_OUTPUT_BUFFERS    = 64;         // keep this number of unused buffers 
        internal const int CHAR_BUFFER_SIZE           = 1024;       // size of the buffers for chat conversion to bytes
        internal const int MAX_FREE_CHAR_BUFFERS      = 64;         // keep this number of unused buffers
        internal const int MAX_BYTES_TO_COPY          = 128;        // copy results of char conversion vs using recycleable buffers
        internal const int MAX_RESOURCE_BYTES_TO_COPY = 4*1024;       // resource strings below this size are copied to buffers 

        static BufferingParams() { 
            Version osVer = Environment.OSVersion.Version; 

            if (osVer.Major == 6 && osVer.Minor > 0) { 
                // DevDiv Bug# 219960
                // The slightly smaller buffer (< 0x3fe0) qualifies for the "Low-Fragmentation-Heap" in windows 7.
                // The LFH heap has path and scalability advantages and does not trigger aggressive
                // decommit logic now present in the Windows 7 heap. 
                INTEGRATED_MODE_BUFFER_SIZE = 16*1024 - 4*IntPtr.Size - 16*7;
            } 
            else { 
                INTEGRATED_MODE_BUFFER_SIZE = 16*1024 - 4*IntPtr.Size;
            } 
        }
    }

    /* 
     * Interface implemented by elements of the response buffer list
     */ 
    internal interface IHttpResponseElement { 
        long GetSize();
        byte[] GetBytes();                   // required for filtering 
        void Send(HttpWorkerRequest wr);
    }

    /* 
     * Base class for recyclable memory buffer elements
     */ 
    internal abstract class HttpBaseMemoryResponseBufferElement { 

        protected int _size; 
        protected int _free;
        protected bool _recycle;

        internal int FreeBytes { 
            get { return _free;}
        } 
 
        internal void DisableRecycling() {
            _recycle = false; 
        }

        // abstract methods
 
        internal abstract void Recycle();
 
        internal abstract HttpResponseBufferElement Clone(); 

        internal abstract int Append(byte[] data, int offset, int size); 

        internal abstract int Append(IntPtr data, int offset, int size);

        internal abstract void AppendEncodedChars(char[] data, int offset, int size, Encoder encoder, bool flushEncoder); 
    }
 
    /* 
     * Memory response buffer
     */ 
    internal sealed class HttpResponseBufferElement : HttpBaseMemoryResponseBufferElement, IHttpResponseElement {
        private byte[] _data;

        private static UbyteBufferAllocator s_Allocator = 
        new UbyteBufferAllocator(BufferingParams.OUTPUT_BUFFER_SIZE,
                                 BufferingParams.MAX_FREE_OUTPUT_BUFFERS); 
 

#if UNUSED 
        /*
         * Constructor that creates an empty buffer
         */
        internal HttpResponseBufferElement() { 
            _data = (byte[])s_Allocator.GetBuffer();
            _size = BufferingParams.OUTPUT_BUFFER_SIZE; 
            _free = _size; 
            _recycle = true;
        } 
#endif

        /*
         * Constructor that accepts the data buffer and holds on to it 
         */
        internal HttpResponseBufferElement(byte[] data, int size) { 
            _data = data; 
            _size = size;
            _free = 0; 
            _recycle = false;
        }

        /* 
         *  Close the buffer copying the data
         *  (needed to 'compress' buffers for caching) 
         */ 

        internal override HttpResponseBufferElement Clone() { 
            int clonedSize = _size - _free;
            byte[] clonedData = new byte[clonedSize];
            Buffer.BlockCopy(_data, 0, clonedData, 0, clonedSize);
            return new HttpResponseBufferElement(clonedData, clonedSize); 
        }
 
        internal override void Recycle() { 
            // Since the no-arg constructor has been #ifdef'd out, _recycle will
            // always be false, so this block will never be executed. 
#if UNUSED
            if (_recycle && _data != null) {
                s_Allocator.ReuseBuffer(_data);
                _data = null; 
                _free = 0;
                _recycle = false; 
            } 
#endif
        } 

        internal override int Append(byte[] data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Buffer.BlockCopy(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        internal override int Append(IntPtr data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Misc.CopyMemory(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        internal override void AppendEncodedChars(char[] data, int offset, int size, Encoder encoder, bool flushEncoder) {
            int byteSize = encoder.GetBytes(data, offset, size, _data, _size-_free, flushEncoder);
            _free -= byteSize; 
        }
 
        // 
        // IHttpResponseElement implementation
        // 

        /*
         * Get number of bytes
         */ 
        long IHttpResponseElement.GetSize() {
            return(_size - _free); 
        } 

        /* 
         * Get bytes (for filtering)
         */
        byte[] IHttpResponseElement.GetBytes() {
            return _data; 
        }
 
        /* 
         * Write HttpWorkerRequest
         */ 
        void IHttpResponseElement.Send(HttpWorkerRequest wr) {
            int n = _size - _free;
            if (n > 0)
                wr.SendResponseFromMemory(_data, n); 
        }
    } 
 
#if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
    /* 
     * Unmanaged memory response buffer
     */
    internal sealed class HttpResponseUnmanagedBufferElement : HttpBaseMemoryResponseBufferElement, IHttpResponseElement {
        private IntPtr _data; 
        private static IntPtr s_Pool;
 
        static HttpResponseUnmanagedBufferElement() { 
            if (HttpRuntime.UseIntegratedPipeline) {
                s_Pool = IIS.MgdGetBufferPool(BufferingParams.INTEGRATED_MODE_BUFFER_SIZE); 
            }
            else {
                s_Pool = UnsafeNativeMethods.BufferPoolGetPool(BufferingParams.OUTPUT_BUFFER_SIZE,
                    BufferingParams.MAX_FREE_OUTPUT_BUFFERS); 

            } 
        } 

        /* 
         * Constructor that creates an empty buffer
         */
        internal HttpResponseUnmanagedBufferElement() {
            if (HttpRuntime.UseIntegratedPipeline) { 
                _data = IIS.MgdGetBuffer(s_Pool);
                _size = BufferingParams.INTEGRATED_MODE_BUFFER_SIZE; 
            } 
            else {
                _data = UnsafeNativeMethods.BufferPoolGetBuffer(s_Pool); 
                _size = BufferingParams.OUTPUT_BUFFER_SIZE;
            }
            if (_data == IntPtr.Zero) {
                throw new OutOfMemoryException(); 
            }
            _free = _size; 
            _recycle = true; 
        }
 
        /*
         * dtor - frees the unmanaged buffer
         */
        ~HttpResponseUnmanagedBufferElement() { 
            IntPtr data = Interlocked.Exchange(ref _data, IntPtr.Zero);
            if (data != IntPtr.Zero) { 
                if (HttpRuntime.UseIntegratedPipeline) { 
                    IIS.MgdReturnBuffer(data);
                } 
                else {
                    UnsafeNativeMethods.BufferPoolReleaseBuffer(data);
                }
            } 
        }
 
        /* 
         *  Clone the buffer copying the data int managed buffer
         *  (needed to 'compress' buffers for caching) 
         */
        internal override HttpResponseBufferElement Clone() {
            int clonedSize = _size - _free;
            byte[] clonedData = new byte[clonedSize]; 
            Misc.CopyMemory(_data, 0, clonedData, 0, clonedSize);
            return new HttpResponseBufferElement(clonedData, clonedSize); 
        } 

        internal override void Recycle() { 
            if (_recycle)
                ForceRecycle();
        }
 
        private void ForceRecycle() {
            IntPtr data = Interlocked.Exchange(ref _data, IntPtr.Zero); 
            if (data != IntPtr.Zero) { 
                _free = 0;
                _recycle = false; 
                if (HttpRuntime.UseIntegratedPipeline) {
                    IIS.MgdReturnBuffer(data);
                }
                else { 
                    UnsafeNativeMethods.BufferPoolReleaseBuffer(data);
                } 
                System.GC.SuppressFinalize(this); 
            }
        } 

        internal override int Append(byte[] data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Misc.CopyMemory(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        internal override int Append(IntPtr data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Misc.CopyMemory(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        // manually adjust the size
        // used after file reads directly into a buffer
        internal void AdjustSize(int size) { 
            _free -= size;
        } 
 
        internal override void AppendEncodedChars(char[] data, int offset, int size, Encoder encoder, bool flushEncoder) {
            int byteSize = UnsafeAppendEncodedChars(data, offset, size, _data, _size - _free, _free, encoder, flushEncoder); 
            _free -= byteSize;
#if DBG
            Debug.Trace("UnmanagedBuffers", "Encoding chars, charCount=" + size + ", byteCount=" + byteSize);
#endif 
        }
 
        private unsafe static int UnsafeAppendEncodedChars(char[] src, int srcOffset, int srcSize, IntPtr dest, int destOffset, int destSize, Encoder encoder, bool flushEncoder) { 
            int numBytes = 0;
 
            byte* destBytes = ((byte*)dest) + destOffset;

            fixed (char* charSrc = src) {
                numBytes = encoder.GetBytes(charSrc+srcOffset, srcSize, destBytes, destSize, flushEncoder); 
            }
 
            return numBytes; 
        }
 
        //
        // IHttpResponseElement implementation
        //
 
        /*
         * Get number of bytes 
         */ 
        long IHttpResponseElement.GetSize() {
            return (_size - _free); 
        }

        /*
         * Get bytes (for filtering) 
         */
        byte[] IHttpResponseElement.GetBytes() { 
            int n = (_size - _free); 

            if (n > 0) { 
                byte[] data = new byte[n];
                Misc.CopyMemory(_data, 0, data, 0, n);
                return data;
            } 
            else {
                return null; 
            } 
        }
 
        /*
         * Write HttpWorkerRequest
         */
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            int n = _size - _free;
 
            if (n > 0) { 
                wr.SendResponseFromMemory(_data, n, true);
            } 

#if DBG
            Debug.Trace("UnmanagedBuffers", "Sending data, byteCount=" + n + ", freeBytes=" + _free);
#endif 
        }
 
        internal unsafe IntPtr FreeLocation { 
            get {
                int n = _size - _free; 
                byte * p = (byte*) _data.ToPointer();
                p += n;

                return new IntPtr(p); 
            }
        } 
    } 

#endif // !FEATURE_PAL 
    /*
     * Response element where data comes from resource
     */
    internal sealed class HttpResourceResponseElement : IHttpResponseElement { 
        private IntPtr _data;
        private int   _offset; 
        private int   _size; 

        internal HttpResourceResponseElement(IntPtr data, int offset, int size) { 
            _data = data;
            _offset = offset;
            _size = size;
        } 

        // 
        // IHttpResponseElement implementation 
        //
 
        /*
         * Get number of bytes
         */
        long IHttpResponseElement.GetSize() { 
            return _size;
        } 
 
        /*
         * Get bytes (used only for filtering) 
         */
        byte[] IHttpResponseElement.GetBytes() {
            if (_size > 0) {
                byte[] data = new byte[_size]; 
                Misc.CopyMemory(_data, _offset, data, 0, _size);
                return data; 
            } 
            else {
                return null; 
            }
        }

        /* 
         * Write HttpWorkerRequest
         */ 
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            if (_size > 0) {
                wr.SendResponseFromMemory(new IntPtr(_data.ToInt64()+_offset), _size); 
            }
        }
    }
 
    /*
     * Response element where data comes from file 
     */ 
    internal sealed class HttpFileResponseElement : IHttpResponseElement {
        private String _filename; 
        private long   _offset;
        private long   _size;
        private bool   _isImpersonating;
        private bool   _useTransmitFile; 

        /** 
         * Constructor from filename, uses TransmitFile 
         */
        internal HttpFileResponseElement(String filename, long offset, long size, bool isImpersonating, bool supportsLongTransmitFile) : 
            this (filename, offset, size, isImpersonating, true, supportsLongTransmitFile) {
        }

        /* 
         * Constructor from filename and range (doesn't use TransmitFile)
         */ 
        internal HttpFileResponseElement(String filename, long offset, long size) : 
            this (filename, offset, size, false, false, false) {
        } 

        private HttpFileResponseElement(string filename,
                                        long offset,
                                        long size, 
                                        bool isImpersonating,
                                        bool useTransmitFile, 
                                        bool supportsLongTransmitFile) 
        {
            if ((!supportsLongTransmitFile && size > Int32.MaxValue) || (size < 0)) { 
                throw new ArgumentOutOfRangeException("size", size, SR.GetString(SR.Invalid_size));
            }
            if ((!supportsLongTransmitFile && offset > Int32.MaxValue) || (offset < 0)) {
                throw new ArgumentOutOfRangeException("offset", offset, SR.GetString(SR.Invalid_size)); 
            }
            _filename = filename; 
            _offset = offset; 
            _size = size;
            _isImpersonating = isImpersonating; 
            _useTransmitFile = useTransmitFile;
        }

        // 
        // IHttpResponseElement implementation
        // 
 
        /*
         * Get number of bytes 
         */
        long IHttpResponseElement.GetSize() {
            return _size;
        } 

        /* 
         * Get bytes (for filtering) 
         */
        byte[] IHttpResponseElement.GetBytes() { 
            if (_size == 0)
                return null;

            byte[] data = null; 
            FileStream f = null;
 
            try { 
                f = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.Read);
 
                long fileSize = f.Length;

                if (_offset < 0 || _size > fileSize - _offset)
                    throw new HttpException(SR.GetString(SR.Invalid_range)); 

                if (_offset > 0) 
                    f.Seek(_offset, SeekOrigin.Begin); 

                int intSize = (int)_size; 
                data = new byte[intSize];
                int bytesRead = 0;
                do {
                    int n = f.Read(data, bytesRead, intSize); 
                    if (n == 0) {
                        break; 
                    } 
                    bytesRead += n;
                    intSize -= n; 
                } while (intSize > 0);
                // Technically here, the buffer may not be full after the loop, but we choose to ignore
                // this very rare condition (the file became shorter between the time we looked at its length
                // and the moment we read it). In this case, we would just have a few zero bytes at the end 
                // of the byte[], which is fine.
            } 
            finally { 
                if (f != null)
                    f.Close(); 
            }

            return data;
        } 

        /* 
         * Write HttpWorkerRequest 
         */
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            if (_size > 0) {
                if (_useTransmitFile) {
                    wr.TransmitFile(_filename, _offset, _size, _isImpersonating); // This is for IIS 6, in-proc TransmitFile
                } 
                else {
                    wr.SendResponseFromFile(_filename, _offset, _size); 
                } 
            }
        } 

    }

    /* 
     * Response element for substituiton
     */ 
    internal sealed class HttpSubstBlockResponseElement : IHttpResponseElement { 
        private HttpResponseSubstitutionCallback _callback;
        private IHttpResponseElement _firstSubstitution; 
        private IntPtr _firstSubstData;
        private int _firstSubstDataSize;
        private bool _isIIS7WorkerRequest;
 
        /*
         * Constructor given the name and the data (fill char converted to bytes) 
         * holds on to the data 
         */
        internal HttpSubstBlockResponseElement(HttpResponseSubstitutionCallback callback, Encoding encoding, Encoder encoder, IIS7WorkerRequest iis7WorkerRequest) { 
            _callback = callback;
            if (iis7WorkerRequest != null) {
                _isIIS7WorkerRequest = true;
                String s = _callback(HttpContext.Current); 
                if (s == null) {
                    throw new ArgumentNullException("substitutionString"); 
                } 
                CreateFirstSubstData(s, iis7WorkerRequest, encoder);
            } 
            else {
                _firstSubstitution = Substitute(encoding);
            }
        } 

        // WOS 1926509: ASP.NET:  WriteSubstitution in integrated mode needs to support callbacks that return String.Empty 
        private unsafe void CreateFirstSubstData(String s, IIS7WorkerRequest iis7WorkerRequest, Encoder encoder) { 
            Debug.Assert(s != null, "s != null");
 
            IntPtr pbBuffer;
            int numBytes = 0;
            int cch = s.Length;
            if (cch > 0) { 
                fixed (char * pch = s) {
                    int cbBuffer = encoder.GetByteCount(pch, cch, true /*flush*/); 
                    pbBuffer = iis7WorkerRequest.AllocateRequestMemory(cbBuffer); 
                    if (pbBuffer != IntPtr.Zero) {
                        numBytes = encoder.GetBytes(pch, cch, (byte*)pbBuffer, cbBuffer, true /*flush*/); 
                    }
                }
            }
            else { 
                // deal with empty string
                pbBuffer = iis7WorkerRequest.AllocateRequestMemory(1); 
            } 

            if (pbBuffer == IntPtr.Zero) { 
                throw new OutOfMemoryException();
            }
            _firstSubstData = pbBuffer;
            _firstSubstDataSize = numBytes; 
        }
 
        /* 
         * Performs substition -- return the resulting HttpResponseBufferElement
         * holds on to the data 
         */
        internal IHttpResponseElement Substitute(Encoding e) {
            String s = _callback(HttpContext.Current);
            byte[] data = e.GetBytes(s); 
            return new HttpResponseBufferElement(data, data.Length);
        } 
 
        internal bool PointerEquals(IntPtr ptr) {
            Debug.Assert(HttpRuntime.UseIntegratedPipeline, "HttpRuntime.UseIntegratedPipeline"); 
            return _firstSubstData == ptr;
        }

        // 
        // IHttpResponseElement implementation (doesn't do anything)
        // 
 
        /*
         * Get number of bytes 
         */
        long IHttpResponseElement.GetSize() {
            if (_isIIS7WorkerRequest) {
                return _firstSubstDataSize; 
            }
            else { 
                return _firstSubstitution.GetSize(); 
            }
        } 

        /*
         * Get bytes (for filtering)
         */ 
        byte[] IHttpResponseElement.GetBytes() {
            if (_isIIS7WorkerRequest) { 
                if (_firstSubstDataSize > 0) { 
                    byte[] data = new byte[_firstSubstDataSize];
                    Misc.CopyMemory(_firstSubstData, 0, data, 0, _firstSubstDataSize); 
                    return data;
                }
                else {
                    // WOS 1926509: ASP.NET:  WriteSubstitution in integrated mode needs to support callbacks that return String.Empty 
                    return (_firstSubstData == IntPtr.Zero) ? null : new byte[0];
                } 
            } 
            else {
                return _firstSubstitution.GetBytes(); 
            }
        }

        /* 
         * Write HttpWorkerRequest
         */ 
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            if (_isIIS7WorkerRequest) {
                IIS7WorkerRequest iis7WorkerRequest = wr as IIS7WorkerRequest; 
                if (iis7WorkerRequest != null) {
                    // buffer can have size of zero if the subst block is an emptry string
                    iis7WorkerRequest.SendResponseFromIISAllocatedRequestMemory(_firstSubstData, _firstSubstDataSize);
                } 
            }
            else { 
                _firstSubstitution.Send(wr); 
            }
        } 
    }

    /*
     * Stream object synchronized with Writer 
     */
    internal class HttpResponseStream : Stream { 
        private HttpWriter _writer; 

        internal HttpResponseStream(HttpWriter writer) { 
            _writer = writer;
        }

        // 
        // Public Stream method implementations
        // 
 
        public override bool CanRead {
            get { return false;} 
        }

        public override bool CanSeek {
            get { return false;} 
        }
 
        public override bool CanWrite { 
            get { return true;}
        } 

        public override long Length {
            get {throw new NotSupportedException();}
        } 

        public override long Position { 
            get {throw new NotSupportedException();} 

            set {throw new NotSupportedException();} 
        }

        protected override void Dispose(bool disposing) {
            try { 
                if (disposing)
                    _writer.Close(); 
            } 
            finally {
                base.Dispose(disposing); 
            }
        }

        public override void Flush() { 
            _writer.Flush();
        } 
 
        public override long Seek(long offset, SeekOrigin origin) {
            throw new NotSupportedException(); 
        }

        public override void SetLength(long value) {
            throw new NotSupportedException(); 
        }
 
        public override int Read(byte[] buffer, int offset, int count) { 
            throw new NotSupportedException();
        } 

        public override void Write(byte[] buffer, int offset, int count) {
            if (_writer.IgnoringFurtherWrites) {
                return; 
            }
 
            if (buffer == null) { 
                throw new ArgumentNullException("buffer");
            } 
            int len = buffer.Length - offset;
            if ((offset < 0) || (len <= 0)) {
                throw new ArgumentOutOfRangeException("offset");
            } 
            if (count < 0) {
                throw new ArgumentOutOfRangeException("count"); 
            } 

            if (len < count) 
                count = len;

            _writer.WriteFromStream(buffer, offset, count);
        } 
    }
 
    /* 
     * Stream serving as sink for filters
     */ 
    internal sealed class HttpResponseStreamFilterSink : HttpResponseStream {
        private bool _filtering = false;

        internal HttpResponseStreamFilterSink(HttpWriter writer) : base(writer) { 
        }
 
        private void VerifyState() { 
            // throw exception on unexpected filter writes
 
            if (!_filtering)
                throw new HttpException(SR.GetString(SR.Invalid_use_of_response_filter));
        }
 
        internal bool Filtering {
            get { return _filtering;} 
            set { _filtering = value;} 
        }
 
        //
        // Stream methods just go to the base class with exception of Close and Flush that do nothing
        //
 
        protected override void Dispose(bool disposing) {
            // do nothing 
            base.Dispose(disposing); 
        }
 
        public override void Flush() {
            // do nothing (this is not a buffering stream)
        }
 
        public override void Write(byte[] buffer, int offset, int count) {
            VerifyState(); 
            base.Write(buffer, offset, count); 
        }
    } 

    /*
     * TextWriter synchronized with the response object
     */ 

    ///  
    ///    A TextWriter class synchronized with the Response object. 
    /// 
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class HttpWriter : TextWriter {
        private HttpResponse _response;
        private HttpResponseStream _stream;
 
        private HttpResponseStreamFilterSink _filterSink;       // sink stream for the filter writes
        private Stream                       _installedFilter;  // installed filtering stream 
 
        private HttpBaseMemoryResponseBufferElement _lastBuffer;
        private ArrayList _buffers; 

        private char[] _charBuffer;
        private int _charBufferLength;
        private int _charBufferFree; 
        private ArrayList _substElements = null;
 
        private static CharBufferAllocator s_Allocator = 
        new CharBufferAllocator(BufferingParams.CHAR_BUFFER_SIZE,
                                BufferingParams.MAX_FREE_CHAR_BUFFERS); 

        // cached data from the response
        // can be invalidated via UpdateResponseXXX methods
 
        private bool _responseBufferingOn;
        private Encoding _responseEncoding; 
        private bool     _responseEncodingUsed; 
        private bool     _responseEncodingUpdated;
        private Encoder  _responseEncoder; 
        private int      _responseCodePage;
        private bool     _responseCodePageIsAsciiCompat;

        private bool _ignoringFurtherWrites; 

        private bool _hasBeenClearedRecently; 
 
        internal HttpWriter(HttpResponse response): base(null) {
            _response = response; 
            _stream = new HttpResponseStream(this);

            _buffers = new ArrayList();
            _lastBuffer = null; 

            _charBuffer = (char[])s_Allocator.GetBuffer(); 
            _charBufferLength = _charBuffer.Length; 
            _charBufferFree = _charBufferLength;
 
            UpdateResponseBuffering();

            // delay getting response encoding until it is really needed
            // UpdateResponseEncoding(); 
        }
 
        internal ArrayList SubstElements { 
            get {
                if (_substElements == null) { 
                    _substElements = new ArrayList();
                    // dynamic compression is not compatible with post cache substitution
                    _response.Context.Request.SetDynamicCompression(false /*enable*/);
                } 
                return _substElements;
            } 
        } 

        ///  
        /// True if the writer is ignoring all writes
        /// 
        internal bool IgnoringFurtherWrites {
            get { 
                return _ignoringFurtherWrites;
            } 
        } 

        ///  
        /// 
        internal void IgnoreFurtherWrites() {
            _ignoringFurtherWrites = true;
        } 

        internal void UpdateResponseBuffering() { 
            _responseBufferingOn = _response.BufferOutput; 
        }
 
        internal void UpdateResponseEncoding() {
            if (_responseEncodingUpdated) {  // subsequent update
                if (_charBufferLength != _charBufferFree)
                    FlushCharBuffer(true); 
            }
 
            _responseEncoding = _response.ContentEncoding; 
            _responseEncoder = _response.ContentEncoder;
            _responseCodePage = _responseEncoding.CodePage; 
            _responseCodePageIsAsciiCompat = CodePageUtils.IsAsciiCompatibleCodePage(_responseCodePage);
            _responseEncodingUpdated = true;
        }
 

        ///  
        ///    [To be supplied.] 
        /// 
        public override Encoding Encoding { 
            get {
                if (!_responseEncodingUpdated) {
                    UpdateResponseEncoding();
                } 

                return _responseEncoding; 
            } 
        }
 
        internal Encoder Encoder {
            get {
                if (!_responseEncodingUpdated) {
                    UpdateResponseEncoding(); 
                }
                return _responseEncoder; 
            } 
        }
 
        private HttpBaseMemoryResponseBufferElement CreateNewMemoryBufferElement() {
            return new HttpResponseUnmanagedBufferElement(); /* using unmanaged buffers */
        }
 
    internal void DisposeIntegratedBuffers() {
            Debug.Assert(HttpRuntime.UseIntegratedPipeline); 
 
            // don't recycle char buffers here (ClearBuffers will)
            // do recycle native output buffers 
            if (_buffers != null) {

                int n = _buffers.Count;
                for (int i = 0; i < n; i++) { 
                    HttpBaseMemoryResponseBufferElement buf = _buffers[i] as HttpBaseMemoryResponseBufferElement;
 
                    // if this is a native buffer, this will bump down the ref count 
                    // the native side also keeps a ref count (see mgdhandler.cxx)
                    if (buf != null) { 
                        buf.Recycle();
                    }
                }
 
                _buffers = null;
            } 
 
            // finish by clearing buffers
            ClearBuffers(); 
    }

        internal void RecycleBuffers() {
            // recycle char buffers 

            if (_charBuffer != null) { 
                s_Allocator.ReuseBuffer(_charBuffer); 
                _charBuffer = null;
            } 

            // recycle output buffers
            RecycleBufferElements();
        } 

        internal void ClearSubstitutionBlocks() { 
            _substElements = null; 
        }
 
        private void RecycleBufferElements() {
            if (_buffers != null) {

                int n = _buffers.Count; 
                for (int i = 0; i < n; i++) {
                    HttpBaseMemoryResponseBufferElement buf = _buffers[i] as HttpBaseMemoryResponseBufferElement; 
                    if (buf != null) { 
                        buf.Recycle();
                    } 
                }

                _buffers = null;
            } 
        }
 
        private void ClearCharBuffer() { 
            _charBufferFree = _charBufferLength;
        } 

        private void FlushCharBuffer(bool flushEncoder) {
            int numChars = _charBufferLength - _charBufferFree;
 
            Debug.Assert(numChars > 0);
 
            // remember that response required encoding (to indicate the charset= is needed) 
            if (!_responseEncodingUpdated) {
                UpdateResponseEncoding(); 
            }

            _responseEncodingUsed = true;
 
            // estimate conversion size
            int estByteSize = _responseEncoding.GetMaxByteCount(numChars); 
 
            if (estByteSize <= BufferingParams.MAX_BYTES_TO_COPY || !_responseBufferingOn) {
                // small size -- allocate intermediate buffer and copy into the output buffer 
                byte[] byteBuffer = new byte[estByteSize];
                int realByteSize = _responseEncoder.GetBytes(_charBuffer, 0, numChars,
                                                             byteBuffer, 0, flushEncoder);
                BufferData(byteBuffer, 0, realByteSize, false); 
            }
            else { 
                // convert right into the output buffer 

                int free = (_lastBuffer != null) ? _lastBuffer.FreeBytes : 0; 

                if (free < estByteSize) {
                    // need new buffer -- last one doesn't have enough space
                    _lastBuffer = CreateNewMemoryBufferElement(); 
                    _buffers.Add(_lastBuffer);
                    free = _lastBuffer.FreeBytes; 
                } 

                // byte buffers must be long enough to keep everything in char buffer 
                Debug.Assert(free >= estByteSize);
                _lastBuffer.AppendEncodedChars(_charBuffer, 0, numChars, _responseEncoder, flushEncoder);
            }
 
            _charBufferFree = _charBufferLength;
        } 
 
        private void BufferData(byte[] data, int offset, int size, bool needToCopyData) {
            int n; 

            // try last buffer
            if (_lastBuffer != null) {
                n = _lastBuffer.Append(data, offset, size); 
                size -= n;
                offset += n; 
            } 
            else if (!needToCopyData && offset == 0 && !_responseBufferingOn) {
                // when not buffering, there is no need for big buffer accumulating multiple writes 
                // the byte[] data can be sent as is

                _buffers.Add(new HttpResponseBufferElement(data, size));
                return; 
            }
 
            // do other buffers if needed 
            while (size > 0) {
                _lastBuffer = CreateNewMemoryBufferElement(); 
                _buffers.Add(_lastBuffer);
                n = _lastBuffer.Append(data, offset, size);
                offset += n;
                size -= n; 
            }
        } 
 
        private void BufferResource(IntPtr data, int offset, int size) {
            if (size > BufferingParams.MAX_RESOURCE_BYTES_TO_COPY || !_responseBufferingOn) { 
                // for long response strings create its own buffer element to avoid copy cost
                // also, when not buffering, no need for an extra copy (nothing will get accumulated anyway)
                _lastBuffer = null;
                _buffers.Add(new HttpResourceResponseElement(data, offset, size)); 
                return;
            } 
 
            int n;
 
            // try last buffer
            if (_lastBuffer != null) {
                n = _lastBuffer.Append(data, offset, size);
                size -= n; 
                offset += n;
            } 
 
            // do other buffers if needed
            while (size > 0) { 
                _lastBuffer = CreateNewMemoryBufferElement();
                _buffers.Add(_lastBuffer);
                n = _lastBuffer.Append(data, offset, size);
                offset += n; 
                size -= n;
            } 
        } 

        // 
        // 'Write' methods to be called from other internal classes
        //

        internal void WriteFromStream(byte[] data, int offset, int size) { 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 
 
            BufferData(data, offset, size, true);
 
            if (!_responseBufferingOn)
                _response.Flush();
        }
 
        internal void WriteUTF8ResourceString(IntPtr pv, int offset, int size, bool asciiOnly) {
 
            if (!_responseEncodingUpdated) { 
                UpdateResponseEncoding();
            } 

            if (_responseCodePage == CodePageUtils.CodePageUT8 || // response encoding is UTF8
                (asciiOnly && _responseCodePageIsAsciiCompat)) {  // ASCII resource and ASCII-compat encoding
 
                _responseEncodingUsed = true;  // note the we used encoding (means that we need to generate charset=) see RAID#93415
 
                // write bytes directly 
                if (_charBufferLength != _charBufferFree)
                    FlushCharBuffer(true); 

                BufferResource(pv, offset, size);

                if (!_responseBufferingOn) 
                    _response.Flush();
            } 
            else { 
                // have to re-encode with response's encoding -- use public Write(String)
                Write(StringResourceManager.ResourceToString(pv, offset, size)); 
            }
        }

        internal void TransmitFile(string filename, long offset, long size, bool isImpersonating, bool supportsLongTransmitFile) { 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 
 
            _lastBuffer = null;
            _buffers.Add(new HttpFileResponseElement(filename, offset, size, isImpersonating, supportsLongTransmitFile)); 

            if (!_responseBufferingOn)
                _response.Flush();
        } 

        internal void WriteFile(String filename, long offset, long size) { 
            if (_charBufferLength != _charBufferFree) 
                FlushCharBuffer(true);
 
            _lastBuffer = null;
            _buffers.Add(new HttpFileResponseElement(filename, offset, size));

            if (!_responseBufferingOn) 
                _response.Flush();
        } 
 
        //
        // Support for substitution blocks 
        //

        internal void WriteSubstBlock(HttpResponseSubstitutionCallback callback, IIS7WorkerRequest iis7WorkerRequest) {
            if (_charBufferLength != _charBufferFree) 
                FlushCharBuffer(true);
            _lastBuffer = null; 
 
            // add new substitution block to the buffer list
            IHttpResponseElement element = new HttpSubstBlockResponseElement(callback, Encoding, Encoder, iis7WorkerRequest); 
            _buffers.Add(element);

            if (iis7WorkerRequest != null) {
                SubstElements.Add(element); 
            }
 
            if (!_responseBufferingOn) 
                _response.Flush();
        } 

        //
        // Support for response buffer manipulation: HasBeenClearedRecently, GetResponseBufferCountAfterFlush,
        // and MoveResponseBufferRangeForward.  The intended use of these functions is to rearrange 
        // the order of the buffers.  Improper use of these functions may result in excessive memory use.
        // They were added specifically so that custom hidden form data could be moved to the beginning 
        // of the form. 

        internal bool HasBeenClearedRecently { 
            get {
                return _hasBeenClearedRecently;
            }
            set { 
                _hasBeenClearedRecently = value;
            } 
        } 

        // Gets the response buffer count after flushing the char buffer.  Note that _lastBuffer is cleared, 
        // and therefore may not be filled, so calling this can lead to inefficient use of response buffers.
        internal int GetResponseBufferCountAfterFlush() {
            if (_charBufferLength != _charBufferFree) {
                FlushCharBuffer(true); 
            }
 
            // set _lastBuffer to null to prevent more data from being added to it 
            _lastBuffer = null;
 
            return _buffers.Count;
        }

        // Move the specified range of buffers forward in the buffer list. 
        internal void MoveResponseBufferRangeForward(int srcIndex, int srcCount, int dstIndex) {
            Debug.Assert(dstIndex <= srcIndex); 
 
            // DevDiv Bugs 154630: No need to copy the form between temporary array and the buffer list when
            // no hidden fields are written. 
            if (srcCount > 0) {
                // create temporary storage for buffers that will be moved backwards
                object[] temp = new object[srcIndex - dstIndex];
 
                // copy buffers that will be moved backwards
                _buffers.CopyTo(dstIndex, temp, 0, temp.Length); 
 
                // move the range forward from srcIndex to dstIndex
                for (int i = 0; i < srcCount; i++) { 
                    _buffers[dstIndex + i] = _buffers[srcIndex + i];
                }

                // insert buffers that were placed in temporary storage 
                for (int i = 0; i < temp.Length; i++) {
                    _buffers[dstIndex + srcCount + i] = temp[i]; 
                } 
            }
 
            // set _lastBuffer
            HttpBaseMemoryResponseBufferElement buf = _buffers[_buffers.Count-1] as HttpBaseMemoryResponseBufferElement;
            if (buf != null && buf.FreeBytes > 0) {
                _lastBuffer = buf; 
            }
            else { 
                _lastBuffer = null; 
            }
        } 

        //
        // Buffer management
        // 

        internal void ClearBuffers() { 
            ClearCharBuffer(); 

            // re-enable dynamic compression if we are about to clear substitution blocks 
            if (_substElements != null) {
                _response.Context.Request.SetDynamicCompression(true /*enable*/);
            }
 
            //VSWhidbey 559434: Private Bytes goes thru roof because unmanaged buffers are not recycled when Response.Flush is called
            RecycleBufferElements(); 
 
            _buffers = new ArrayList();
            _lastBuffer = null; 
            _hasBeenClearedRecently = true;
        }

        internal long GetBufferedLength() { 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 
 
            long size = 0;
            if (_buffers != null) { 
                int n = _buffers.Count;
                for (int i = 0; i < n; i++) {
                    size += ((IHttpResponseElement)_buffers[i]).GetSize();
                } 
            }
            return size; 
        } 

        internal bool ResponseEncodingUsed { 
            get { return _responseEncodingUsed; }
        }

        // in integrated mode, snapshots need to pull the chunks from the IIS 
        // buffers since they may have already been pushed through
        // Therefore, we can't rely solely on what's in the HttpWriter 
        // at the moment 
        internal ArrayList GetIntegratedSnapshot(out bool hasSubstBlocks, IIS7WorkerRequest wr) {
            ArrayList buffers = null; 

            // first, get what's in our buffers
            ArrayList writerBuffers = GetSnapshot(out hasSubstBlocks);
 
            // now, get what's in the IIS buffers
            ArrayList nativeBuffers = wr.GetBufferedResponseChunks(true, _substElements, ref hasSubstBlocks); 
 
            // try to append the current buffers to what we just
            // got from the native buffer 
            if (null != nativeBuffers) {
                for (int i = 0; i < writerBuffers.Count; i++) {
                    nativeBuffers.Add(writerBuffers[i]);
                } 
                buffers = nativeBuffers;
            } 
            else { 
                buffers = writerBuffers;
            } 

            // if we have substitution blocks:
            // 1) throw exception if someone modified the subst blocks
            // 2) re-enable compression 
            if (_substElements != null && _substElements.Count > 0) {
                int substCount = 0; 
                // scan buffers for subst blocks 
                for(int i = 0; i < buffers.Count; i++) {
                    if (buffers[i] is HttpSubstBlockResponseElement) { 
                        substCount++;
                        if (substCount == _substElements.Count) {
                            break;
                        } 
                    }
                } 
 
                if (substCount != _substElements.Count) {
                    throw new InvalidOperationException(SR.GetString(SR.Substitution_blocks_cannot_be_modified)); 
                }

                // re-enable dynamic compression when we have a snapshot of the subst blocks.
                _response.Context.Request.SetDynamicCompression(true /*enable*/); 
            }
 
            return buffers; 
        }
 
        //
        //  Snapshot for caching
        //
 
        internal ArrayList GetSnapshot(out bool hasSubstBlocks) {
            if (_charBufferLength != _charBufferFree) 
                FlushCharBuffer(true); 

            _lastBuffer = null; // to make sure nothing gets appended after 

            hasSubstBlocks = false;

            ArrayList buffers = new ArrayList(); 

            // copy buffer references to the returned list, make non-recyclable 
            int n = _buffers.Count; 
            for (int i = 0; i < n; i++) {
                Object responseElement = _buffers[i]; 

                HttpBaseMemoryResponseBufferElement buffer = responseElement as HttpBaseMemoryResponseBufferElement;

                if (buffer != null) { 
                    if (buffer.FreeBytes > BufferingParams.MAX_FREE_BYTES_TO_CACHE) {
                        // copy data if too much is free 
                        responseElement = buffer.Clone(); 
                    }
                    else { 
                        // cache the buffer as is with free bytes
                        buffer.DisableRecycling();
                    }
                } 
                else if (responseElement is HttpSubstBlockResponseElement) {
                    hasSubstBlocks = true; 
                } 

                buffers.Add(responseElement); 
            }
            return buffers;
        }
 
        internal void UseSnapshot(ArrayList buffers) {
            ClearBuffers(); 
 
            // copy buffer references to the internal buffer list
            // make substitution if needed 

            int n = buffers.Count;
            for (int i = 0; i < n; i++) {
                Object responseElement = buffers[i]; 
                HttpSubstBlockResponseElement substBlock = (responseElement as HttpSubstBlockResponseElement);
 
                if (substBlock != null) { 
                    _buffers.Add(substBlock.Substitute(Encoding));
                } 
                else {
                    _buffers.Add(responseElement);
                }
            } 
        }
 
        // 
        //  Support for response stream filters
        // 

        internal Stream GetCurrentFilter() {
            if (_installedFilter != null)
                return _installedFilter; 

            if (_filterSink == null) 
                _filterSink = new HttpResponseStreamFilterSink(this); 

            return _filterSink; 
        }

        internal bool FilterInstalled {
            get { return (_installedFilter != null); } 
        }
 
        internal void InstallFilter(Stream filter) { 
            if (_filterSink == null)  // have to redirect to the sink -- null means sink wasn't ever asked for
                throw new HttpException(SR.GetString(SR.Invalid_response_filter)); 

            _installedFilter = filter;
        }
 
        internal void Filter(bool finalFiltering) {
            // no filter? 
            if (_installedFilter == null) 
                return;
 
            // flush char buffer and remember old buffers
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true);
 
            _lastBuffer = null;
 
            // no content to filter 
            if (_buffers.Count == 0)
                return; 

            // remember old buffers
            ArrayList oldBuffers = _buffers;
            _buffers = new ArrayList(); 

            // push old buffer list through the filter 
 
            Debug.Assert(_filterSink != null);
 
            _filterSink.Filtering = true;

            try {
                int n = oldBuffers.Count; 
                for (int i = 0; i < n; i++) {
                    IHttpResponseElement buf = (IHttpResponseElement)oldBuffers[i]; 
 
                    long len = buf.GetSize();
 
                    if (len > 0) {
                        // Convert.ToInt32 will throw for sizes larger than Int32.MaxValue.
                        // Filtering large response sizes is not supported
                        _installedFilter.Write(buf.GetBytes(), 0, Convert.ToInt32(len)); 
                    }
                } 
 
                _installedFilter.Flush();
 
            }
            finally {
                try {
                    if (finalFiltering) 
                        _installedFilter.Close();
                } 
                finally { 
                    _filterSink.Filtering = false;
                } 
            }
        }

        internal void FilterIntegrated(bool finalFiltering, IIS7WorkerRequest wr) { 
            // no filter?
            if (_installedFilter == null) 
                return; 

            // flush char buffer and remember old buffers 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true);

            _lastBuffer = null; 

            // ISAPI mode bails if it has no buffers 
            // to filter, in integrated mode we need 
            // to check the unified response buffers
            // maintained by IIS for content, as well 

            // remember current buffers (if any) that might be
            // response entity from this transition
            // (not yet pushed through to IIS response buffers) 
            ArrayList oldBuffers = _buffers;
            _buffers = new ArrayList(); 
 
            // now, get what's in the IIS buffers
            ArrayList nativeBuffers = null; 
            bool fDummy = false;
            nativeBuffers = wr.GetBufferedResponseChunks(false, null, ref fDummy);

            Debug.Assert(_filterSink != null); 
            _filterSink.Filtering = true;
 
            try { 
                // push buffers through installed filters
                // push the IIS ones through first since we need to maintain order 
                if (null != nativeBuffers) {
                    for (int i = 0; i < nativeBuffers.Count; i++) {
                        IHttpResponseElement buf = (IHttpResponseElement)nativeBuffers[i];
 
                        long len = buf.GetSize();
 
                        if (len > 0) 
                            _installedFilter.Write(buf.GetBytes(), 0, Convert.ToInt32(len));
 
                    }

                    // if we had stuff there, we now need to clear it since we may have
                    // transformed it 
                    wr.ClearResponse(true /* entity */, false /* headers */);
                } 
 
                // current buffers, if any
                if (null != oldBuffers) { 
                    for (int i = 0; i < oldBuffers.Count; i++) {
                        IHttpResponseElement buf = (IHttpResponseElement)oldBuffers[i];

                        long len = buf.GetSize(); 

                        if (len > 0) 
                            _installedFilter.Write(buf.GetBytes(), 0, Convert.ToInt32(len)); 

                    } 
                }

                _installedFilter.Flush();
            } 
            finally {
                try { 
                    if (finalFiltering) 
                        _installedFilter.Close();
                } 
                finally {
                    _filterSink.Filtering = false;
                }
            } 
        }
 
        // 
        //  Send via worker request
        // 

        internal void Send(HttpWorkerRequest wr) {
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 

            int n = _buffers.Count; 
 
            if (n > 0) {
                // write data 
                for (int i = 0; i < n; i++) {
                    ((IHttpResponseElement)_buffers[i]).Send(wr);
                }
            } 
        }
 
        // 
        // Public TextWriter method implementations
        // 


        /// 
        ///     Sends all buffered output to the client and closes the socket connection. 
        /// 
        public override void Close() { 
            // don't do anything (this could called from a wrapping text writer) 
        }
 

        /// 
        ///     Sends all buffered output to the client.
        ///  
        public override void Flush() {
            // don't flush the response 
        } 

 
        /// 
        ///     Sends a character to the client.
        /// 
        public override void Write(char ch) { 
            if (_ignoringFurtherWrites) {
                return; 
            } 

            if (_charBufferFree == 0) { 
                FlushCharBuffer(false);
            }

            _charBuffer[_charBufferLength - _charBufferFree] = ch; 
            _charBufferFree--;
 
            if (!_responseBufferingOn) { 
                _response.Flush();
            } 
        }


        ///  
        ///     Sends a stream of buffered characters to the client
        ///       using starting position and number of characters to send.  
        ///  
        public override void Write(char[] buffer, int index, int count) {
            if (_ignoringFurtherWrites) { 
                return;
            }

            if (buffer == null || index < 0 || count < 0 || 
                buffer.Length - index < count) {
                throw new ArgumentOutOfRangeException("index"); 
            } 

            if (count == 0) 
                return;

            while (count > 0) {
                if (_charBufferFree == 0) { 
                    FlushCharBuffer(false);
                } 
 
                int n = (count < _charBufferFree) ? count : _charBufferFree;
                System.Array.Copy(buffer, index, _charBuffer, _charBufferLength - _charBufferFree, n); 
                _charBufferFree -= n;
                index += n;
                count -= n;
            } 

            if (!_responseBufferingOn) { 
                _response.Flush(); 
            }
        } 


        /// 
        ///    Sends a string to the client. 
        /// 
        public override void Write(String s) { 
            if (_ignoringFurtherWrites) 
                return;
 
            if (s == null)
                return;

            if (s.Length == 0) { 
                // Ensure flush if string is empty
            } 
            else if (s.Length < _charBufferFree) { 
                // fast path - 99% of string writes will not overrun the buffer
                // avoid redundant arg checking in string.CopyTo 
                StringUtil.UnsafeStringCopy(s, 0, _charBuffer, _charBufferLength - _charBufferFree, s.Length);
                _charBufferFree -= s.Length;
            }
            else { 
                int count = s.Length;
                int index = 0; 
                int n; 

                while (count > 0) { 
                    if (_charBufferFree == 0) {
                        FlushCharBuffer(false);
                    }
 
                    n = (count < _charBufferFree) ? count : _charBufferFree;
 
                    // avoid redundant arg checking in string.CopyTo 
                    StringUtil.UnsafeStringCopy(s, index, _charBuffer, _charBufferLength - _charBufferFree, n);
 
                    _charBufferFree -= n;
                    index += n;
                    count -= n;
                } 
            }
 
            if (!_responseBufferingOn) { 
                _response.Flush();
            } 
        }


        ///  
        ///    Sends a string or a sub-string to the client.
        ///  
        public void WriteString(String s, int index, int count) { 
            if (s == null)
                return; 

            if (index < 0) {
                throw new ArgumentOutOfRangeException("index");
            } 

            if (count < 0) { 
                throw new ArgumentOutOfRangeException("count"); 
            }
 
            if (index + count > s.Length) {
                throw new ArgumentOutOfRangeException("index");
            }
 
            if (_ignoringFurtherWrites) {
                return; 
            } 

            if (count == 0) { 
                // Ensure flush if string is empty
            }
            else if (count < _charBufferFree) {
                // fast path - 99% of string writes will not overrun the buffer 
                // avoid redundant arg checking in string.CopyTo
                StringUtil.UnsafeStringCopy(s, index, _charBuffer, _charBufferLength - _charBufferFree, count); 
                _charBufferFree -= count; 
            }
            else { 
                int n;

                while (count > 0) {
                    if (_charBufferFree == 0) { 
                        FlushCharBuffer(false);
                    } 
 
                    n = (count < _charBufferFree) ? count : _charBufferFree;
 
                    // avoid redundant arg checking in string.CopyTo
                    StringUtil.UnsafeStringCopy(s, index, _charBuffer, _charBufferLength - _charBufferFree, n);

                    _charBufferFree -= n; 
                    index += n;
                    count -= n; 
                } 
            }
 
            if (!_responseBufferingOn) {
                _response.Flush();
            }
        } 

 
        ///  
        ///    Sends an object to the client.
        ///  
        public override void Write(Object obj) {
            if (_ignoringFurtherWrites) {
                return;
            } 

            if (obj != null) 
                Write(obj.ToString()); 
        }
 
        //
        // Support for binary data
        //
 

        ///  
        ///    Sends a buffered stream of bytes to the client. 
        /// 
        public void WriteBytes(byte[] buffer, int index, int count) { 
            if (_ignoringFurtherWrites) {
                return;
            }
 
            WriteFromStream(buffer, index, count);
        } 
 

        ///  
        ///    Writes out a CRLF pair into the the stream.
        /// 
        public override void WriteLine() {
            if (_ignoringFurtherWrites) { 
                return;
            } 
 
            // It turns out this is way more efficient than the TextWriter version of
            // WriteLine which ends up calling Write with a 2 char array 

            if (_charBufferFree < 2)
                FlushCharBuffer(false);
 
            int pos = _charBufferLength - _charBufferFree;
            _charBuffer[pos] = '\r'; 
            _charBuffer[pos + 1] = '\n'; 
            _charBufferFree -= 2;
 
            if (!_responseBufferingOn)
                _response.Flush();
        }
 
        /*
         * The Stream for writing binary data 
         */ 

        ///  
        ///     Enables binary output to the client.
        /// 
            public Stream OutputStream {
            get { return _stream;} 
        }
 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 * Response Writer and Stream implementation 
 *
 * Copyright (c) 1998 Microsoft Corporation 
 */

namespace System.Web {
    using System.Collections; 
    using System.Globalization;
    using System.IO; 
    using System.Runtime.Serialization.Formatters; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Threading;
    using System.Web.Util;
    using System.Web.Hosting;
 
    using IIS = System.Web.Hosting.UnsafeIISMethods;
 
    // 
    //  HttpWriter buffer recycling support
    // 

    /*
     * Constants for buffering
     */ 
    internal static class BufferingParams {
        internal static readonly int INTEGRATED_MODE_BUFFER_SIZE;   // native buffer size for integrated mode 
        internal const int OUTPUT_BUFFER_SIZE         = 31*1024;    // output is a chain of this size buffers 
        internal const int MAX_FREE_BYTES_TO_CACHE    = 4096;       // don't compress when taking snapshot if free bytes < this
        internal const int MAX_FREE_OUTPUT_BUFFERS    = 64;         // keep this number of unused buffers 
        internal const int CHAR_BUFFER_SIZE           = 1024;       // size of the buffers for chat conversion to bytes
        internal const int MAX_FREE_CHAR_BUFFERS      = 64;         // keep this number of unused buffers
        internal const int MAX_BYTES_TO_COPY          = 128;        // copy results of char conversion vs using recycleable buffers
        internal const int MAX_RESOURCE_BYTES_TO_COPY = 4*1024;       // resource strings below this size are copied to buffers 

        static BufferingParams() { 
            Version osVer = Environment.OSVersion.Version; 

            if (osVer.Major == 6 && osVer.Minor > 0) { 
                // DevDiv Bug# 219960
                // The slightly smaller buffer (< 0x3fe0) qualifies for the "Low-Fragmentation-Heap" in windows 7.
                // The LFH heap has path and scalability advantages and does not trigger aggressive
                // decommit logic now present in the Windows 7 heap. 
                INTEGRATED_MODE_BUFFER_SIZE = 16*1024 - 4*IntPtr.Size - 16*7;
            } 
            else { 
                INTEGRATED_MODE_BUFFER_SIZE = 16*1024 - 4*IntPtr.Size;
            } 
        }
    }

    /* 
     * Interface implemented by elements of the response buffer list
     */ 
    internal interface IHttpResponseElement { 
        long GetSize();
        byte[] GetBytes();                   // required for filtering 
        void Send(HttpWorkerRequest wr);
    }

    /* 
     * Base class for recyclable memory buffer elements
     */ 
    internal abstract class HttpBaseMemoryResponseBufferElement { 

        protected int _size; 
        protected int _free;
        protected bool _recycle;

        internal int FreeBytes { 
            get { return _free;}
        } 
 
        internal void DisableRecycling() {
            _recycle = false; 
        }

        // abstract methods
 
        internal abstract void Recycle();
 
        internal abstract HttpResponseBufferElement Clone(); 

        internal abstract int Append(byte[] data, int offset, int size); 

        internal abstract int Append(IntPtr data, int offset, int size);

        internal abstract void AppendEncodedChars(char[] data, int offset, int size, Encoder encoder, bool flushEncoder); 
    }
 
    /* 
     * Memory response buffer
     */ 
    internal sealed class HttpResponseBufferElement : HttpBaseMemoryResponseBufferElement, IHttpResponseElement {
        private byte[] _data;

        private static UbyteBufferAllocator s_Allocator = 
        new UbyteBufferAllocator(BufferingParams.OUTPUT_BUFFER_SIZE,
                                 BufferingParams.MAX_FREE_OUTPUT_BUFFERS); 
 

#if UNUSED 
        /*
         * Constructor that creates an empty buffer
         */
        internal HttpResponseBufferElement() { 
            _data = (byte[])s_Allocator.GetBuffer();
            _size = BufferingParams.OUTPUT_BUFFER_SIZE; 
            _free = _size; 
            _recycle = true;
        } 
#endif

        /*
         * Constructor that accepts the data buffer and holds on to it 
         */
        internal HttpResponseBufferElement(byte[] data, int size) { 
            _data = data; 
            _size = size;
            _free = 0; 
            _recycle = false;
        }

        /* 
         *  Close the buffer copying the data
         *  (needed to 'compress' buffers for caching) 
         */ 

        internal override HttpResponseBufferElement Clone() { 
            int clonedSize = _size - _free;
            byte[] clonedData = new byte[clonedSize];
            Buffer.BlockCopy(_data, 0, clonedData, 0, clonedSize);
            return new HttpResponseBufferElement(clonedData, clonedSize); 
        }
 
        internal override void Recycle() { 
            // Since the no-arg constructor has been #ifdef'd out, _recycle will
            // always be false, so this block will never be executed. 
#if UNUSED
            if (_recycle && _data != null) {
                s_Allocator.ReuseBuffer(_data);
                _data = null; 
                _free = 0;
                _recycle = false; 
            } 
#endif
        } 

        internal override int Append(byte[] data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Buffer.BlockCopy(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        internal override int Append(IntPtr data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Misc.CopyMemory(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        internal override void AppendEncodedChars(char[] data, int offset, int size, Encoder encoder, bool flushEncoder) {
            int byteSize = encoder.GetBytes(data, offset, size, _data, _size-_free, flushEncoder);
            _free -= byteSize; 
        }
 
        // 
        // IHttpResponseElement implementation
        // 

        /*
         * Get number of bytes
         */ 
        long IHttpResponseElement.GetSize() {
            return(_size - _free); 
        } 

        /* 
         * Get bytes (for filtering)
         */
        byte[] IHttpResponseElement.GetBytes() {
            return _data; 
        }
 
        /* 
         * Write HttpWorkerRequest
         */ 
        void IHttpResponseElement.Send(HttpWorkerRequest wr) {
            int n = _size - _free;
            if (n > 0)
                wr.SendResponseFromMemory(_data, n); 
        }
    } 
 
#if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
    /* 
     * Unmanaged memory response buffer
     */
    internal sealed class HttpResponseUnmanagedBufferElement : HttpBaseMemoryResponseBufferElement, IHttpResponseElement {
        private IntPtr _data; 
        private static IntPtr s_Pool;
 
        static HttpResponseUnmanagedBufferElement() { 
            if (HttpRuntime.UseIntegratedPipeline) {
                s_Pool = IIS.MgdGetBufferPool(BufferingParams.INTEGRATED_MODE_BUFFER_SIZE); 
            }
            else {
                s_Pool = UnsafeNativeMethods.BufferPoolGetPool(BufferingParams.OUTPUT_BUFFER_SIZE,
                    BufferingParams.MAX_FREE_OUTPUT_BUFFERS); 

            } 
        } 

        /* 
         * Constructor that creates an empty buffer
         */
        internal HttpResponseUnmanagedBufferElement() {
            if (HttpRuntime.UseIntegratedPipeline) { 
                _data = IIS.MgdGetBuffer(s_Pool);
                _size = BufferingParams.INTEGRATED_MODE_BUFFER_SIZE; 
            } 
            else {
                _data = UnsafeNativeMethods.BufferPoolGetBuffer(s_Pool); 
                _size = BufferingParams.OUTPUT_BUFFER_SIZE;
            }
            if (_data == IntPtr.Zero) {
                throw new OutOfMemoryException(); 
            }
            _free = _size; 
            _recycle = true; 
        }
 
        /*
         * dtor - frees the unmanaged buffer
         */
        ~HttpResponseUnmanagedBufferElement() { 
            IntPtr data = Interlocked.Exchange(ref _data, IntPtr.Zero);
            if (data != IntPtr.Zero) { 
                if (HttpRuntime.UseIntegratedPipeline) { 
                    IIS.MgdReturnBuffer(data);
                } 
                else {
                    UnsafeNativeMethods.BufferPoolReleaseBuffer(data);
                }
            } 
        }
 
        /* 
         *  Clone the buffer copying the data int managed buffer
         *  (needed to 'compress' buffers for caching) 
         */
        internal override HttpResponseBufferElement Clone() {
            int clonedSize = _size - _free;
            byte[] clonedData = new byte[clonedSize]; 
            Misc.CopyMemory(_data, 0, clonedData, 0, clonedSize);
            return new HttpResponseBufferElement(clonedData, clonedSize); 
        } 

        internal override void Recycle() { 
            if (_recycle)
                ForceRecycle();
        }
 
        private void ForceRecycle() {
            IntPtr data = Interlocked.Exchange(ref _data, IntPtr.Zero); 
            if (data != IntPtr.Zero) { 
                _free = 0;
                _recycle = false; 
                if (HttpRuntime.UseIntegratedPipeline) {
                    IIS.MgdReturnBuffer(data);
                }
                else { 
                    UnsafeNativeMethods.BufferPoolReleaseBuffer(data);
                } 
                System.GC.SuppressFinalize(this); 
            }
        } 

        internal override int Append(byte[] data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Misc.CopyMemory(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        internal override int Append(IntPtr data, int offset, int size) {
            if (_free == 0 || size == 0)
                return 0; 
            int n = (_free >= size) ? size : _free;
            Misc.CopyMemory(data, offset, _data, _size-_free, n); 
            _free -= n; 
            return n;
        } 

        // manually adjust the size
        // used after file reads directly into a buffer
        internal void AdjustSize(int size) { 
            _free -= size;
        } 
 
        internal override void AppendEncodedChars(char[] data, int offset, int size, Encoder encoder, bool flushEncoder) {
            int byteSize = UnsafeAppendEncodedChars(data, offset, size, _data, _size - _free, _free, encoder, flushEncoder); 
            _free -= byteSize;
#if DBG
            Debug.Trace("UnmanagedBuffers", "Encoding chars, charCount=" + size + ", byteCount=" + byteSize);
#endif 
        }
 
        private unsafe static int UnsafeAppendEncodedChars(char[] src, int srcOffset, int srcSize, IntPtr dest, int destOffset, int destSize, Encoder encoder, bool flushEncoder) { 
            int numBytes = 0;
 
            byte* destBytes = ((byte*)dest) + destOffset;

            fixed (char* charSrc = src) {
                numBytes = encoder.GetBytes(charSrc+srcOffset, srcSize, destBytes, destSize, flushEncoder); 
            }
 
            return numBytes; 
        }
 
        //
        // IHttpResponseElement implementation
        //
 
        /*
         * Get number of bytes 
         */ 
        long IHttpResponseElement.GetSize() {
            return (_size - _free); 
        }

        /*
         * Get bytes (for filtering) 
         */
        byte[] IHttpResponseElement.GetBytes() { 
            int n = (_size - _free); 

            if (n > 0) { 
                byte[] data = new byte[n];
                Misc.CopyMemory(_data, 0, data, 0, n);
                return data;
            } 
            else {
                return null; 
            } 
        }
 
        /*
         * Write HttpWorkerRequest
         */
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            int n = _size - _free;
 
            if (n > 0) { 
                wr.SendResponseFromMemory(_data, n, true);
            } 

#if DBG
            Debug.Trace("UnmanagedBuffers", "Sending data, byteCount=" + n + ", freeBytes=" + _free);
#endif 
        }
 
        internal unsafe IntPtr FreeLocation { 
            get {
                int n = _size - _free; 
                byte * p = (byte*) _data.ToPointer();
                p += n;

                return new IntPtr(p); 
            }
        } 
    } 

#endif // !FEATURE_PAL 
    /*
     * Response element where data comes from resource
     */
    internal sealed class HttpResourceResponseElement : IHttpResponseElement { 
        private IntPtr _data;
        private int   _offset; 
        private int   _size; 

        internal HttpResourceResponseElement(IntPtr data, int offset, int size) { 
            _data = data;
            _offset = offset;
            _size = size;
        } 

        // 
        // IHttpResponseElement implementation 
        //
 
        /*
         * Get number of bytes
         */
        long IHttpResponseElement.GetSize() { 
            return _size;
        } 
 
        /*
         * Get bytes (used only for filtering) 
         */
        byte[] IHttpResponseElement.GetBytes() {
            if (_size > 0) {
                byte[] data = new byte[_size]; 
                Misc.CopyMemory(_data, _offset, data, 0, _size);
                return data; 
            } 
            else {
                return null; 
            }
        }

        /* 
         * Write HttpWorkerRequest
         */ 
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            if (_size > 0) {
                wr.SendResponseFromMemory(new IntPtr(_data.ToInt64()+_offset), _size); 
            }
        }
    }
 
    /*
     * Response element where data comes from file 
     */ 
    internal sealed class HttpFileResponseElement : IHttpResponseElement {
        private String _filename; 
        private long   _offset;
        private long   _size;
        private bool   _isImpersonating;
        private bool   _useTransmitFile; 

        /** 
         * Constructor from filename, uses TransmitFile 
         */
        internal HttpFileResponseElement(String filename, long offset, long size, bool isImpersonating, bool supportsLongTransmitFile) : 
            this (filename, offset, size, isImpersonating, true, supportsLongTransmitFile) {
        }

        /* 
         * Constructor from filename and range (doesn't use TransmitFile)
         */ 
        internal HttpFileResponseElement(String filename, long offset, long size) : 
            this (filename, offset, size, false, false, false) {
        } 

        private HttpFileResponseElement(string filename,
                                        long offset,
                                        long size, 
                                        bool isImpersonating,
                                        bool useTransmitFile, 
                                        bool supportsLongTransmitFile) 
        {
            if ((!supportsLongTransmitFile && size > Int32.MaxValue) || (size < 0)) { 
                throw new ArgumentOutOfRangeException("size", size, SR.GetString(SR.Invalid_size));
            }
            if ((!supportsLongTransmitFile && offset > Int32.MaxValue) || (offset < 0)) {
                throw new ArgumentOutOfRangeException("offset", offset, SR.GetString(SR.Invalid_size)); 
            }
            _filename = filename; 
            _offset = offset; 
            _size = size;
            _isImpersonating = isImpersonating; 
            _useTransmitFile = useTransmitFile;
        }

        // 
        // IHttpResponseElement implementation
        // 
 
        /*
         * Get number of bytes 
         */
        long IHttpResponseElement.GetSize() {
            return _size;
        } 

        /* 
         * Get bytes (for filtering) 
         */
        byte[] IHttpResponseElement.GetBytes() { 
            if (_size == 0)
                return null;

            byte[] data = null; 
            FileStream f = null;
 
            try { 
                f = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.Read);
 
                long fileSize = f.Length;

                if (_offset < 0 || _size > fileSize - _offset)
                    throw new HttpException(SR.GetString(SR.Invalid_range)); 

                if (_offset > 0) 
                    f.Seek(_offset, SeekOrigin.Begin); 

                int intSize = (int)_size; 
                data = new byte[intSize];
                int bytesRead = 0;
                do {
                    int n = f.Read(data, bytesRead, intSize); 
                    if (n == 0) {
                        break; 
                    } 
                    bytesRead += n;
                    intSize -= n; 
                } while (intSize > 0);
                // Technically here, the buffer may not be full after the loop, but we choose to ignore
                // this very rare condition (the file became shorter between the time we looked at its length
                // and the moment we read it). In this case, we would just have a few zero bytes at the end 
                // of the byte[], which is fine.
            } 
            finally { 
                if (f != null)
                    f.Close(); 
            }

            return data;
        } 

        /* 
         * Write HttpWorkerRequest 
         */
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            if (_size > 0) {
                if (_useTransmitFile) {
                    wr.TransmitFile(_filename, _offset, _size, _isImpersonating); // This is for IIS 6, in-proc TransmitFile
                } 
                else {
                    wr.SendResponseFromFile(_filename, _offset, _size); 
                } 
            }
        } 

    }

    /* 
     * Response element for substituiton
     */ 
    internal sealed class HttpSubstBlockResponseElement : IHttpResponseElement { 
        private HttpResponseSubstitutionCallback _callback;
        private IHttpResponseElement _firstSubstitution; 
        private IntPtr _firstSubstData;
        private int _firstSubstDataSize;
        private bool _isIIS7WorkerRequest;
 
        /*
         * Constructor given the name and the data (fill char converted to bytes) 
         * holds on to the data 
         */
        internal HttpSubstBlockResponseElement(HttpResponseSubstitutionCallback callback, Encoding encoding, Encoder encoder, IIS7WorkerRequest iis7WorkerRequest) { 
            _callback = callback;
            if (iis7WorkerRequest != null) {
                _isIIS7WorkerRequest = true;
                String s = _callback(HttpContext.Current); 
                if (s == null) {
                    throw new ArgumentNullException("substitutionString"); 
                } 
                CreateFirstSubstData(s, iis7WorkerRequest, encoder);
            } 
            else {
                _firstSubstitution = Substitute(encoding);
            }
        } 

        // WOS 1926509: ASP.NET:  WriteSubstitution in integrated mode needs to support callbacks that return String.Empty 
        private unsafe void CreateFirstSubstData(String s, IIS7WorkerRequest iis7WorkerRequest, Encoder encoder) { 
            Debug.Assert(s != null, "s != null");
 
            IntPtr pbBuffer;
            int numBytes = 0;
            int cch = s.Length;
            if (cch > 0) { 
                fixed (char * pch = s) {
                    int cbBuffer = encoder.GetByteCount(pch, cch, true /*flush*/); 
                    pbBuffer = iis7WorkerRequest.AllocateRequestMemory(cbBuffer); 
                    if (pbBuffer != IntPtr.Zero) {
                        numBytes = encoder.GetBytes(pch, cch, (byte*)pbBuffer, cbBuffer, true /*flush*/); 
                    }
                }
            }
            else { 
                // deal with empty string
                pbBuffer = iis7WorkerRequest.AllocateRequestMemory(1); 
            } 

            if (pbBuffer == IntPtr.Zero) { 
                throw new OutOfMemoryException();
            }
            _firstSubstData = pbBuffer;
            _firstSubstDataSize = numBytes; 
        }
 
        /* 
         * Performs substition -- return the resulting HttpResponseBufferElement
         * holds on to the data 
         */
        internal IHttpResponseElement Substitute(Encoding e) {
            String s = _callback(HttpContext.Current);
            byte[] data = e.GetBytes(s); 
            return new HttpResponseBufferElement(data, data.Length);
        } 
 
        internal bool PointerEquals(IntPtr ptr) {
            Debug.Assert(HttpRuntime.UseIntegratedPipeline, "HttpRuntime.UseIntegratedPipeline"); 
            return _firstSubstData == ptr;
        }

        // 
        // IHttpResponseElement implementation (doesn't do anything)
        // 
 
        /*
         * Get number of bytes 
         */
        long IHttpResponseElement.GetSize() {
            if (_isIIS7WorkerRequest) {
                return _firstSubstDataSize; 
            }
            else { 
                return _firstSubstitution.GetSize(); 
            }
        } 

        /*
         * Get bytes (for filtering)
         */ 
        byte[] IHttpResponseElement.GetBytes() {
            if (_isIIS7WorkerRequest) { 
                if (_firstSubstDataSize > 0) { 
                    byte[] data = new byte[_firstSubstDataSize];
                    Misc.CopyMemory(_firstSubstData, 0, data, 0, _firstSubstDataSize); 
                    return data;
                }
                else {
                    // WOS 1926509: ASP.NET:  WriteSubstitution in integrated mode needs to support callbacks that return String.Empty 
                    return (_firstSubstData == IntPtr.Zero) ? null : new byte[0];
                } 
            } 
            else {
                return _firstSubstitution.GetBytes(); 
            }
        }

        /* 
         * Write HttpWorkerRequest
         */ 
        void IHttpResponseElement.Send(HttpWorkerRequest wr) { 
            if (_isIIS7WorkerRequest) {
                IIS7WorkerRequest iis7WorkerRequest = wr as IIS7WorkerRequest; 
                if (iis7WorkerRequest != null) {
                    // buffer can have size of zero if the subst block is an emptry string
                    iis7WorkerRequest.SendResponseFromIISAllocatedRequestMemory(_firstSubstData, _firstSubstDataSize);
                } 
            }
            else { 
                _firstSubstitution.Send(wr); 
            }
        } 
    }

    /*
     * Stream object synchronized with Writer 
     */
    internal class HttpResponseStream : Stream { 
        private HttpWriter _writer; 

        internal HttpResponseStream(HttpWriter writer) { 
            _writer = writer;
        }

        // 
        // Public Stream method implementations
        // 
 
        public override bool CanRead {
            get { return false;} 
        }

        public override bool CanSeek {
            get { return false;} 
        }
 
        public override bool CanWrite { 
            get { return true;}
        } 

        public override long Length {
            get {throw new NotSupportedException();}
        } 

        public override long Position { 
            get {throw new NotSupportedException();} 

            set {throw new NotSupportedException();} 
        }

        protected override void Dispose(bool disposing) {
            try { 
                if (disposing)
                    _writer.Close(); 
            } 
            finally {
                base.Dispose(disposing); 
            }
        }

        public override void Flush() { 
            _writer.Flush();
        } 
 
        public override long Seek(long offset, SeekOrigin origin) {
            throw new NotSupportedException(); 
        }

        public override void SetLength(long value) {
            throw new NotSupportedException(); 
        }
 
        public override int Read(byte[] buffer, int offset, int count) { 
            throw new NotSupportedException();
        } 

        public override void Write(byte[] buffer, int offset, int count) {
            if (_writer.IgnoringFurtherWrites) {
                return; 
            }
 
            if (buffer == null) { 
                throw new ArgumentNullException("buffer");
            } 
            int len = buffer.Length - offset;
            if ((offset < 0) || (len <= 0)) {
                throw new ArgumentOutOfRangeException("offset");
            } 
            if (count < 0) {
                throw new ArgumentOutOfRangeException("count"); 
            } 

            if (len < count) 
                count = len;

            _writer.WriteFromStream(buffer, offset, count);
        } 
    }
 
    /* 
     * Stream serving as sink for filters
     */ 
    internal sealed class HttpResponseStreamFilterSink : HttpResponseStream {
        private bool _filtering = false;

        internal HttpResponseStreamFilterSink(HttpWriter writer) : base(writer) { 
        }
 
        private void VerifyState() { 
            // throw exception on unexpected filter writes
 
            if (!_filtering)
                throw new HttpException(SR.GetString(SR.Invalid_use_of_response_filter));
        }
 
        internal bool Filtering {
            get { return _filtering;} 
            set { _filtering = value;} 
        }
 
        //
        // Stream methods just go to the base class with exception of Close and Flush that do nothing
        //
 
        protected override void Dispose(bool disposing) {
            // do nothing 
            base.Dispose(disposing); 
        }
 
        public override void Flush() {
            // do nothing (this is not a buffering stream)
        }
 
        public override void Write(byte[] buffer, int offset, int count) {
            VerifyState(); 
            base.Write(buffer, offset, count); 
        }
    } 

    /*
     * TextWriter synchronized with the response object
     */ 

    ///  
    ///    A TextWriter class synchronized with the Response object. 
    /// 
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class HttpWriter : TextWriter {
        private HttpResponse _response;
        private HttpResponseStream _stream;
 
        private HttpResponseStreamFilterSink _filterSink;       // sink stream for the filter writes
        private Stream                       _installedFilter;  // installed filtering stream 
 
        private HttpBaseMemoryResponseBufferElement _lastBuffer;
        private ArrayList _buffers; 

        private char[] _charBuffer;
        private int _charBufferLength;
        private int _charBufferFree; 
        private ArrayList _substElements = null;
 
        private static CharBufferAllocator s_Allocator = 
        new CharBufferAllocator(BufferingParams.CHAR_BUFFER_SIZE,
                                BufferingParams.MAX_FREE_CHAR_BUFFERS); 

        // cached data from the response
        // can be invalidated via UpdateResponseXXX methods
 
        private bool _responseBufferingOn;
        private Encoding _responseEncoding; 
        private bool     _responseEncodingUsed; 
        private bool     _responseEncodingUpdated;
        private Encoder  _responseEncoder; 
        private int      _responseCodePage;
        private bool     _responseCodePageIsAsciiCompat;

        private bool _ignoringFurtherWrites; 

        private bool _hasBeenClearedRecently; 
 
        internal HttpWriter(HttpResponse response): base(null) {
            _response = response; 
            _stream = new HttpResponseStream(this);

            _buffers = new ArrayList();
            _lastBuffer = null; 

            _charBuffer = (char[])s_Allocator.GetBuffer(); 
            _charBufferLength = _charBuffer.Length; 
            _charBufferFree = _charBufferLength;
 
            UpdateResponseBuffering();

            // delay getting response encoding until it is really needed
            // UpdateResponseEncoding(); 
        }
 
        internal ArrayList SubstElements { 
            get {
                if (_substElements == null) { 
                    _substElements = new ArrayList();
                    // dynamic compression is not compatible with post cache substitution
                    _response.Context.Request.SetDynamicCompression(false /*enable*/);
                } 
                return _substElements;
            } 
        } 

        ///  
        /// True if the writer is ignoring all writes
        /// 
        internal bool IgnoringFurtherWrites {
            get { 
                return _ignoringFurtherWrites;
            } 
        } 

        ///  
        /// 
        internal void IgnoreFurtherWrites() {
            _ignoringFurtherWrites = true;
        } 

        internal void UpdateResponseBuffering() { 
            _responseBufferingOn = _response.BufferOutput; 
        }
 
        internal void UpdateResponseEncoding() {
            if (_responseEncodingUpdated) {  // subsequent update
                if (_charBufferLength != _charBufferFree)
                    FlushCharBuffer(true); 
            }
 
            _responseEncoding = _response.ContentEncoding; 
            _responseEncoder = _response.ContentEncoder;
            _responseCodePage = _responseEncoding.CodePage; 
            _responseCodePageIsAsciiCompat = CodePageUtils.IsAsciiCompatibleCodePage(_responseCodePage);
            _responseEncodingUpdated = true;
        }
 

        ///  
        ///    [To be supplied.] 
        /// 
        public override Encoding Encoding { 
            get {
                if (!_responseEncodingUpdated) {
                    UpdateResponseEncoding();
                } 

                return _responseEncoding; 
            } 
        }
 
        internal Encoder Encoder {
            get {
                if (!_responseEncodingUpdated) {
                    UpdateResponseEncoding(); 
                }
                return _responseEncoder; 
            } 
        }
 
        private HttpBaseMemoryResponseBufferElement CreateNewMemoryBufferElement() {
            return new HttpResponseUnmanagedBufferElement(); /* using unmanaged buffers */
        }
 
    internal void DisposeIntegratedBuffers() {
            Debug.Assert(HttpRuntime.UseIntegratedPipeline); 
 
            // don't recycle char buffers here (ClearBuffers will)
            // do recycle native output buffers 
            if (_buffers != null) {

                int n = _buffers.Count;
                for (int i = 0; i < n; i++) { 
                    HttpBaseMemoryResponseBufferElement buf = _buffers[i] as HttpBaseMemoryResponseBufferElement;
 
                    // if this is a native buffer, this will bump down the ref count 
                    // the native side also keeps a ref count (see mgdhandler.cxx)
                    if (buf != null) { 
                        buf.Recycle();
                    }
                }
 
                _buffers = null;
            } 
 
            // finish by clearing buffers
            ClearBuffers(); 
    }

        internal void RecycleBuffers() {
            // recycle char buffers 

            if (_charBuffer != null) { 
                s_Allocator.ReuseBuffer(_charBuffer); 
                _charBuffer = null;
            } 

            // recycle output buffers
            RecycleBufferElements();
        } 

        internal void ClearSubstitutionBlocks() { 
            _substElements = null; 
        }
 
        private void RecycleBufferElements() {
            if (_buffers != null) {

                int n = _buffers.Count; 
                for (int i = 0; i < n; i++) {
                    HttpBaseMemoryResponseBufferElement buf = _buffers[i] as HttpBaseMemoryResponseBufferElement; 
                    if (buf != null) { 
                        buf.Recycle();
                    } 
                }

                _buffers = null;
            } 
        }
 
        private void ClearCharBuffer() { 
            _charBufferFree = _charBufferLength;
        } 

        private void FlushCharBuffer(bool flushEncoder) {
            int numChars = _charBufferLength - _charBufferFree;
 
            Debug.Assert(numChars > 0);
 
            // remember that response required encoding (to indicate the charset= is needed) 
            if (!_responseEncodingUpdated) {
                UpdateResponseEncoding(); 
            }

            _responseEncodingUsed = true;
 
            // estimate conversion size
            int estByteSize = _responseEncoding.GetMaxByteCount(numChars); 
 
            if (estByteSize <= BufferingParams.MAX_BYTES_TO_COPY || !_responseBufferingOn) {
                // small size -- allocate intermediate buffer and copy into the output buffer 
                byte[] byteBuffer = new byte[estByteSize];
                int realByteSize = _responseEncoder.GetBytes(_charBuffer, 0, numChars,
                                                             byteBuffer, 0, flushEncoder);
                BufferData(byteBuffer, 0, realByteSize, false); 
            }
            else { 
                // convert right into the output buffer 

                int free = (_lastBuffer != null) ? _lastBuffer.FreeBytes : 0; 

                if (free < estByteSize) {
                    // need new buffer -- last one doesn't have enough space
                    _lastBuffer = CreateNewMemoryBufferElement(); 
                    _buffers.Add(_lastBuffer);
                    free = _lastBuffer.FreeBytes; 
                } 

                // byte buffers must be long enough to keep everything in char buffer 
                Debug.Assert(free >= estByteSize);
                _lastBuffer.AppendEncodedChars(_charBuffer, 0, numChars, _responseEncoder, flushEncoder);
            }
 
            _charBufferFree = _charBufferLength;
        } 
 
        private void BufferData(byte[] data, int offset, int size, bool needToCopyData) {
            int n; 

            // try last buffer
            if (_lastBuffer != null) {
                n = _lastBuffer.Append(data, offset, size); 
                size -= n;
                offset += n; 
            } 
            else if (!needToCopyData && offset == 0 && !_responseBufferingOn) {
                // when not buffering, there is no need for big buffer accumulating multiple writes 
                // the byte[] data can be sent as is

                _buffers.Add(new HttpResponseBufferElement(data, size));
                return; 
            }
 
            // do other buffers if needed 
            while (size > 0) {
                _lastBuffer = CreateNewMemoryBufferElement(); 
                _buffers.Add(_lastBuffer);
                n = _lastBuffer.Append(data, offset, size);
                offset += n;
                size -= n; 
            }
        } 
 
        private void BufferResource(IntPtr data, int offset, int size) {
            if (size > BufferingParams.MAX_RESOURCE_BYTES_TO_COPY || !_responseBufferingOn) { 
                // for long response strings create its own buffer element to avoid copy cost
                // also, when not buffering, no need for an extra copy (nothing will get accumulated anyway)
                _lastBuffer = null;
                _buffers.Add(new HttpResourceResponseElement(data, offset, size)); 
                return;
            } 
 
            int n;
 
            // try last buffer
            if (_lastBuffer != null) {
                n = _lastBuffer.Append(data, offset, size);
                size -= n; 
                offset += n;
            } 
 
            // do other buffers if needed
            while (size > 0) { 
                _lastBuffer = CreateNewMemoryBufferElement();
                _buffers.Add(_lastBuffer);
                n = _lastBuffer.Append(data, offset, size);
                offset += n; 
                size -= n;
            } 
        } 

        // 
        // 'Write' methods to be called from other internal classes
        //

        internal void WriteFromStream(byte[] data, int offset, int size) { 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 
 
            BufferData(data, offset, size, true);
 
            if (!_responseBufferingOn)
                _response.Flush();
        }
 
        internal void WriteUTF8ResourceString(IntPtr pv, int offset, int size, bool asciiOnly) {
 
            if (!_responseEncodingUpdated) { 
                UpdateResponseEncoding();
            } 

            if (_responseCodePage == CodePageUtils.CodePageUT8 || // response encoding is UTF8
                (asciiOnly && _responseCodePageIsAsciiCompat)) {  // ASCII resource and ASCII-compat encoding
 
                _responseEncodingUsed = true;  // note the we used encoding (means that we need to generate charset=) see RAID#93415
 
                // write bytes directly 
                if (_charBufferLength != _charBufferFree)
                    FlushCharBuffer(true); 

                BufferResource(pv, offset, size);

                if (!_responseBufferingOn) 
                    _response.Flush();
            } 
            else { 
                // have to re-encode with response's encoding -- use public Write(String)
                Write(StringResourceManager.ResourceToString(pv, offset, size)); 
            }
        }

        internal void TransmitFile(string filename, long offset, long size, bool isImpersonating, bool supportsLongTransmitFile) { 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 
 
            _lastBuffer = null;
            _buffers.Add(new HttpFileResponseElement(filename, offset, size, isImpersonating, supportsLongTransmitFile)); 

            if (!_responseBufferingOn)
                _response.Flush();
        } 

        internal void WriteFile(String filename, long offset, long size) { 
            if (_charBufferLength != _charBufferFree) 
                FlushCharBuffer(true);
 
            _lastBuffer = null;
            _buffers.Add(new HttpFileResponseElement(filename, offset, size));

            if (!_responseBufferingOn) 
                _response.Flush();
        } 
 
        //
        // Support for substitution blocks 
        //

        internal void WriteSubstBlock(HttpResponseSubstitutionCallback callback, IIS7WorkerRequest iis7WorkerRequest) {
            if (_charBufferLength != _charBufferFree) 
                FlushCharBuffer(true);
            _lastBuffer = null; 
 
            // add new substitution block to the buffer list
            IHttpResponseElement element = new HttpSubstBlockResponseElement(callback, Encoding, Encoder, iis7WorkerRequest); 
            _buffers.Add(element);

            if (iis7WorkerRequest != null) {
                SubstElements.Add(element); 
            }
 
            if (!_responseBufferingOn) 
                _response.Flush();
        } 

        //
        // Support for response buffer manipulation: HasBeenClearedRecently, GetResponseBufferCountAfterFlush,
        // and MoveResponseBufferRangeForward.  The intended use of these functions is to rearrange 
        // the order of the buffers.  Improper use of these functions may result in excessive memory use.
        // They were added specifically so that custom hidden form data could be moved to the beginning 
        // of the form. 

        internal bool HasBeenClearedRecently { 
            get {
                return _hasBeenClearedRecently;
            }
            set { 
                _hasBeenClearedRecently = value;
            } 
        } 

        // Gets the response buffer count after flushing the char buffer.  Note that _lastBuffer is cleared, 
        // and therefore may not be filled, so calling this can lead to inefficient use of response buffers.
        internal int GetResponseBufferCountAfterFlush() {
            if (_charBufferLength != _charBufferFree) {
                FlushCharBuffer(true); 
            }
 
            // set _lastBuffer to null to prevent more data from being added to it 
            _lastBuffer = null;
 
            return _buffers.Count;
        }

        // Move the specified range of buffers forward in the buffer list. 
        internal void MoveResponseBufferRangeForward(int srcIndex, int srcCount, int dstIndex) {
            Debug.Assert(dstIndex <= srcIndex); 
 
            // DevDiv Bugs 154630: No need to copy the form between temporary array and the buffer list when
            // no hidden fields are written. 
            if (srcCount > 0) {
                // create temporary storage for buffers that will be moved backwards
                object[] temp = new object[srcIndex - dstIndex];
 
                // copy buffers that will be moved backwards
                _buffers.CopyTo(dstIndex, temp, 0, temp.Length); 
 
                // move the range forward from srcIndex to dstIndex
                for (int i = 0; i < srcCount; i++) { 
                    _buffers[dstIndex + i] = _buffers[srcIndex + i];
                }

                // insert buffers that were placed in temporary storage 
                for (int i = 0; i < temp.Length; i++) {
                    _buffers[dstIndex + srcCount + i] = temp[i]; 
                } 
            }
 
            // set _lastBuffer
            HttpBaseMemoryResponseBufferElement buf = _buffers[_buffers.Count-1] as HttpBaseMemoryResponseBufferElement;
            if (buf != null && buf.FreeBytes > 0) {
                _lastBuffer = buf; 
            }
            else { 
                _lastBuffer = null; 
            }
        } 

        //
        // Buffer management
        // 

        internal void ClearBuffers() { 
            ClearCharBuffer(); 

            // re-enable dynamic compression if we are about to clear substitution blocks 
            if (_substElements != null) {
                _response.Context.Request.SetDynamicCompression(true /*enable*/);
            }
 
            //VSWhidbey 559434: Private Bytes goes thru roof because unmanaged buffers are not recycled when Response.Flush is called
            RecycleBufferElements(); 
 
            _buffers = new ArrayList();
            _lastBuffer = null; 
            _hasBeenClearedRecently = true;
        }

        internal long GetBufferedLength() { 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 
 
            long size = 0;
            if (_buffers != null) { 
                int n = _buffers.Count;
                for (int i = 0; i < n; i++) {
                    size += ((IHttpResponseElement)_buffers[i]).GetSize();
                } 
            }
            return size; 
        } 

        internal bool ResponseEncodingUsed { 
            get { return _responseEncodingUsed; }
        }

        // in integrated mode, snapshots need to pull the chunks from the IIS 
        // buffers since they may have already been pushed through
        // Therefore, we can't rely solely on what's in the HttpWriter 
        // at the moment 
        internal ArrayList GetIntegratedSnapshot(out bool hasSubstBlocks, IIS7WorkerRequest wr) {
            ArrayList buffers = null; 

            // first, get what's in our buffers
            ArrayList writerBuffers = GetSnapshot(out hasSubstBlocks);
 
            // now, get what's in the IIS buffers
            ArrayList nativeBuffers = wr.GetBufferedResponseChunks(true, _substElements, ref hasSubstBlocks); 
 
            // try to append the current buffers to what we just
            // got from the native buffer 
            if (null != nativeBuffers) {
                for (int i = 0; i < writerBuffers.Count; i++) {
                    nativeBuffers.Add(writerBuffers[i]);
                } 
                buffers = nativeBuffers;
            } 
            else { 
                buffers = writerBuffers;
            } 

            // if we have substitution blocks:
            // 1) throw exception if someone modified the subst blocks
            // 2) re-enable compression 
            if (_substElements != null && _substElements.Count > 0) {
                int substCount = 0; 
                // scan buffers for subst blocks 
                for(int i = 0; i < buffers.Count; i++) {
                    if (buffers[i] is HttpSubstBlockResponseElement) { 
                        substCount++;
                        if (substCount == _substElements.Count) {
                            break;
                        } 
                    }
                } 
 
                if (substCount != _substElements.Count) {
                    throw new InvalidOperationException(SR.GetString(SR.Substitution_blocks_cannot_be_modified)); 
                }

                // re-enable dynamic compression when we have a snapshot of the subst blocks.
                _response.Context.Request.SetDynamicCompression(true /*enable*/); 
            }
 
            return buffers; 
        }
 
        //
        //  Snapshot for caching
        //
 
        internal ArrayList GetSnapshot(out bool hasSubstBlocks) {
            if (_charBufferLength != _charBufferFree) 
                FlushCharBuffer(true); 

            _lastBuffer = null; // to make sure nothing gets appended after 

            hasSubstBlocks = false;

            ArrayList buffers = new ArrayList(); 

            // copy buffer references to the returned list, make non-recyclable 
            int n = _buffers.Count; 
            for (int i = 0; i < n; i++) {
                Object responseElement = _buffers[i]; 

                HttpBaseMemoryResponseBufferElement buffer = responseElement as HttpBaseMemoryResponseBufferElement;

                if (buffer != null) { 
                    if (buffer.FreeBytes > BufferingParams.MAX_FREE_BYTES_TO_CACHE) {
                        // copy data if too much is free 
                        responseElement = buffer.Clone(); 
                    }
                    else { 
                        // cache the buffer as is with free bytes
                        buffer.DisableRecycling();
                    }
                } 
                else if (responseElement is HttpSubstBlockResponseElement) {
                    hasSubstBlocks = true; 
                } 

                buffers.Add(responseElement); 
            }
            return buffers;
        }
 
        internal void UseSnapshot(ArrayList buffers) {
            ClearBuffers(); 
 
            // copy buffer references to the internal buffer list
            // make substitution if needed 

            int n = buffers.Count;
            for (int i = 0; i < n; i++) {
                Object responseElement = buffers[i]; 
                HttpSubstBlockResponseElement substBlock = (responseElement as HttpSubstBlockResponseElement);
 
                if (substBlock != null) { 
                    _buffers.Add(substBlock.Substitute(Encoding));
                } 
                else {
                    _buffers.Add(responseElement);
                }
            } 
        }
 
        // 
        //  Support for response stream filters
        // 

        internal Stream GetCurrentFilter() {
            if (_installedFilter != null)
                return _installedFilter; 

            if (_filterSink == null) 
                _filterSink = new HttpResponseStreamFilterSink(this); 

            return _filterSink; 
        }

        internal bool FilterInstalled {
            get { return (_installedFilter != null); } 
        }
 
        internal void InstallFilter(Stream filter) { 
            if (_filterSink == null)  // have to redirect to the sink -- null means sink wasn't ever asked for
                throw new HttpException(SR.GetString(SR.Invalid_response_filter)); 

            _installedFilter = filter;
        }
 
        internal void Filter(bool finalFiltering) {
            // no filter? 
            if (_installedFilter == null) 
                return;
 
            // flush char buffer and remember old buffers
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true);
 
            _lastBuffer = null;
 
            // no content to filter 
            if (_buffers.Count == 0)
                return; 

            // remember old buffers
            ArrayList oldBuffers = _buffers;
            _buffers = new ArrayList(); 

            // push old buffer list through the filter 
 
            Debug.Assert(_filterSink != null);
 
            _filterSink.Filtering = true;

            try {
                int n = oldBuffers.Count; 
                for (int i = 0; i < n; i++) {
                    IHttpResponseElement buf = (IHttpResponseElement)oldBuffers[i]; 
 
                    long len = buf.GetSize();
 
                    if (len > 0) {
                        // Convert.ToInt32 will throw for sizes larger than Int32.MaxValue.
                        // Filtering large response sizes is not supported
                        _installedFilter.Write(buf.GetBytes(), 0, Convert.ToInt32(len)); 
                    }
                } 
 
                _installedFilter.Flush();
 
            }
            finally {
                try {
                    if (finalFiltering) 
                        _installedFilter.Close();
                } 
                finally { 
                    _filterSink.Filtering = false;
                } 
            }
        }

        internal void FilterIntegrated(bool finalFiltering, IIS7WorkerRequest wr) { 
            // no filter?
            if (_installedFilter == null) 
                return; 

            // flush char buffer and remember old buffers 
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true);

            _lastBuffer = null; 

            // ISAPI mode bails if it has no buffers 
            // to filter, in integrated mode we need 
            // to check the unified response buffers
            // maintained by IIS for content, as well 

            // remember current buffers (if any) that might be
            // response entity from this transition
            // (not yet pushed through to IIS response buffers) 
            ArrayList oldBuffers = _buffers;
            _buffers = new ArrayList(); 
 
            // now, get what's in the IIS buffers
            ArrayList nativeBuffers = null; 
            bool fDummy = false;
            nativeBuffers = wr.GetBufferedResponseChunks(false, null, ref fDummy);

            Debug.Assert(_filterSink != null); 
            _filterSink.Filtering = true;
 
            try { 
                // push buffers through installed filters
                // push the IIS ones through first since we need to maintain order 
                if (null != nativeBuffers) {
                    for (int i = 0; i < nativeBuffers.Count; i++) {
                        IHttpResponseElement buf = (IHttpResponseElement)nativeBuffers[i];
 
                        long len = buf.GetSize();
 
                        if (len > 0) 
                            _installedFilter.Write(buf.GetBytes(), 0, Convert.ToInt32(len));
 
                    }

                    // if we had stuff there, we now need to clear it since we may have
                    // transformed it 
                    wr.ClearResponse(true /* entity */, false /* headers */);
                } 
 
                // current buffers, if any
                if (null != oldBuffers) { 
                    for (int i = 0; i < oldBuffers.Count; i++) {
                        IHttpResponseElement buf = (IHttpResponseElement)oldBuffers[i];

                        long len = buf.GetSize(); 

                        if (len > 0) 
                            _installedFilter.Write(buf.GetBytes(), 0, Convert.ToInt32(len)); 

                    } 
                }

                _installedFilter.Flush();
            } 
            finally {
                try { 
                    if (finalFiltering) 
                        _installedFilter.Close();
                } 
                finally {
                    _filterSink.Filtering = false;
                }
            } 
        }
 
        // 
        //  Send via worker request
        // 

        internal void Send(HttpWorkerRequest wr) {
            if (_charBufferLength != _charBufferFree)
                FlushCharBuffer(true); 

            int n = _buffers.Count; 
 
            if (n > 0) {
                // write data 
                for (int i = 0; i < n; i++) {
                    ((IHttpResponseElement)_buffers[i]).Send(wr);
                }
            } 
        }
 
        // 
        // Public TextWriter method implementations
        // 


        /// 
        ///     Sends all buffered output to the client and closes the socket connection. 
        /// 
        public override void Close() { 
            // don't do anything (this could called from a wrapping text writer) 
        }
 

        /// 
        ///     Sends all buffered output to the client.
        ///  
        public override void Flush() {
            // don't flush the response 
        } 

 
        /// 
        ///     Sends a character to the client.
        /// 
        public override void Write(char ch) { 
            if (_ignoringFurtherWrites) {
                return; 
            } 

            if (_charBufferFree == 0) { 
                FlushCharBuffer(false);
            }

            _charBuffer[_charBufferLength - _charBufferFree] = ch; 
            _charBufferFree--;
 
            if (!_responseBufferingOn) { 
                _response.Flush();
            } 
        }


        ///  
        ///     Sends a stream of buffered characters to the client
        ///       using starting position and number of characters to send.  
        ///  
        public override void Write(char[] buffer, int index, int count) {
            if (_ignoringFurtherWrites) { 
                return;
            }

            if (buffer == null || index < 0 || count < 0 || 
                buffer.Length - index < count) {
                throw new ArgumentOutOfRangeException("index"); 
            } 

            if (count == 0) 
                return;

            while (count > 0) {
                if (_charBufferFree == 0) { 
                    FlushCharBuffer(false);
                } 
 
                int n = (count < _charBufferFree) ? count : _charBufferFree;
                System.Array.Copy(buffer, index, _charBuffer, _charBufferLength - _charBufferFree, n); 
                _charBufferFree -= n;
                index += n;
                count -= n;
            } 

            if (!_responseBufferingOn) { 
                _response.Flush(); 
            }
        } 


        /// 
        ///    Sends a string to the client. 
        /// 
        public override void Write(String s) { 
            if (_ignoringFurtherWrites) 
                return;
 
            if (s == null)
                return;

            if (s.Length == 0) { 
                // Ensure flush if string is empty
            } 
            else if (s.Length < _charBufferFree) { 
                // fast path - 99% of string writes will not overrun the buffer
                // avoid redundant arg checking in string.CopyTo 
                StringUtil.UnsafeStringCopy(s, 0, _charBuffer, _charBufferLength - _charBufferFree, s.Length);
                _charBufferFree -= s.Length;
            }
            else { 
                int count = s.Length;
                int index = 0; 
                int n; 

                while (count > 0) { 
                    if (_charBufferFree == 0) {
                        FlushCharBuffer(false);
                    }
 
                    n = (count < _charBufferFree) ? count : _charBufferFree;
 
                    // avoid redundant arg checking in string.CopyTo 
                    StringUtil.UnsafeStringCopy(s, index, _charBuffer, _charBufferLength - _charBufferFree, n);
 
                    _charBufferFree -= n;
                    index += n;
                    count -= n;
                } 
            }
 
            if (!_responseBufferingOn) { 
                _response.Flush();
            } 
        }


        ///  
        ///    Sends a string or a sub-string to the client.
        ///  
        public void WriteString(String s, int index, int count) { 
            if (s == null)
                return; 

            if (index < 0) {
                throw new ArgumentOutOfRangeException("index");
            } 

            if (count < 0) { 
                throw new ArgumentOutOfRangeException("count"); 
            }
 
            if (index + count > s.Length) {
                throw new ArgumentOutOfRangeException("index");
            }
 
            if (_ignoringFurtherWrites) {
                return; 
            } 

            if (count == 0) { 
                // Ensure flush if string is empty
            }
            else if (count < _charBufferFree) {
                // fast path - 99% of string writes will not overrun the buffer 
                // avoid redundant arg checking in string.CopyTo
                StringUtil.UnsafeStringCopy(s, index, _charBuffer, _charBufferLength - _charBufferFree, count); 
                _charBufferFree -= count; 
            }
            else { 
                int n;

                while (count > 0) {
                    if (_charBufferFree == 0) { 
                        FlushCharBuffer(false);
                    } 
 
                    n = (count < _charBufferFree) ? count : _charBufferFree;
 
                    // avoid redundant arg checking in string.CopyTo
                    StringUtil.UnsafeStringCopy(s, index, _charBuffer, _charBufferLength - _charBufferFree, n);

                    _charBufferFree -= n; 
                    index += n;
                    count -= n; 
                } 
            }
 
            if (!_responseBufferingOn) {
                _response.Flush();
            }
        } 

 
        ///  
        ///    Sends an object to the client.
        ///  
        public override void Write(Object obj) {
            if (_ignoringFurtherWrites) {
                return;
            } 

            if (obj != null) 
                Write(obj.ToString()); 
        }
 
        //
        // Support for binary data
        //
 

        ///  
        ///    Sends a buffered stream of bytes to the client. 
        /// 
        public void WriteBytes(byte[] buffer, int index, int count) { 
            if (_ignoringFurtherWrites) {
                return;
            }
 
            WriteFromStream(buffer, index, count);
        } 
 

        ///  
        ///    Writes out a CRLF pair into the the stream.
        /// 
        public override void WriteLine() {
            if (_ignoringFurtherWrites) { 
                return;
            } 
 
            // It turns out this is way more efficient than the TextWriter version of
            // WriteLine which ends up calling Write with a 2 char array 

            if (_charBufferFree < 2)
                FlushCharBuffer(false);
 
            int pos = _charBufferLength - _charBufferFree;
            _charBuffer[pos] = '\r'; 
            _charBuffer[pos + 1] = '\n'; 
            _charBufferFree -= 2;
 
            if (!_responseBufferingOn)
                _response.Flush();
        }
 
        /*
         * The Stream for writing binary data 
         */ 

        ///  
        ///     Enables binary output to the client.
        /// 
            public Stream OutputStream {
            get { return _stream;} 
        }
 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK