Exemple #1
0
            private unsafe void UpdateDataChunk()
            {
                if (_dataChunks == null)
                {
                    _dataChunks                  = new Interop.HttpApi.HTTP_DATA_CHUNK[2];
                    _dataChunksGCHandle          = GCHandle.Alloc(_dataChunks, GCHandleType.Pinned);
                    _dataChunks[0]               = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[0].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[1]               = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[1].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                }

                Debug.Assert(_buffer == null || _bufferList == null, "Either 'm_Buffer' or 'm_BufferList' MUST be NULL.");
                Debug.Assert(_shouldCloseOutput || _buffer != null || _bufferList != null, "Either 'm_Buffer' or 'm_BufferList' MUST NOT be NULL.");

                // The underlying byte[] m_Buffer or each m_BufferList[].Array are pinned already
                if (_buffer != null)
                {
                    UpdateDataChunk(0, _buffer, _offset, _count);
                    UpdateDataChunk(1, null, 0, 0);
                    _dataChunkCount = 1;
                }
                else if (_bufferList != null)
                {
                    Debug.Assert(_bufferList != null && _bufferList.Count == 2,
                                 "'m_BufferList' MUST NOT be NULL and have exactly '2' items at this point.");
                    UpdateDataChunk(0, _bufferList[0].Array, _bufferList[0].Offset, _bufferList[0].Count);
                    UpdateDataChunk(1, _bufferList[1].Array, _bufferList[1].Offset, _bufferList[1].Count);
                    _dataChunkCount = 2;
                }
                else
                {
                    Debug.Assert(_shouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'true' at this point.");
                    _dataChunks = null;
                }
            }
Exemple #2
0
        private void WriteCore(byte[] buffer, int offset, int size)
        {
            Interop.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (size == 0 && _leftToWrite != 0)
            {
                return;
            }
            if (_leftToWrite >= 0 && size > _leftToWrite)
            {
                throw new ProtocolViolationException(SR.net_entitytoobig);
            }

            uint statusCode;
            uint dataToWrite = (uint)size;
            SafeLocalAllocHandle?bufferAsIntPtr = null;
            IntPtr pBufferAsIntPtr = IntPtr.Zero;
            bool   sentHeaders     = _httpContext.Response.SentHeaders;

            try
            {
                if (size == 0)
                {
                    statusCode = _httpContext.Response.SendHeaders(null, null, flags, false);
                }
                else
                {
                    fixed(byte *pDataBuffer = buffer)
                    {
                        byte *pBuffer = pDataBuffer;

                        if (_httpContext.Response.BoundaryType == BoundaryType.Chunked)
                        {
                            string chunkHeader = size.ToString("x", CultureInfo.InvariantCulture);
                            dataToWrite     = dataToWrite + (uint)(chunkHeader.Length + 4);
                            bufferAsIntPtr  = SafeLocalAllocHandle.LocalAlloc((int)dataToWrite);
                            pBufferAsIntPtr = bufferAsIntPtr.DangerousGetHandle();
                            for (int i = 0; i < chunkHeader.Length; i++)
                            {
                                Marshal.WriteByte(pBufferAsIntPtr, i, (byte)chunkHeader[i]);
                            }
                            Marshal.WriteInt16(pBufferAsIntPtr, chunkHeader.Length, 0x0A0D);
                            Marshal.Copy(buffer, offset, pBufferAsIntPtr + chunkHeader.Length + 2, size);
                            Marshal.WriteInt16(pBufferAsIntPtr, (int)(dataToWrite - 2), 0x0A0D);
                            pBuffer = (byte *)pBufferAsIntPtr;
                            offset  = 0;
                        }
                        Interop.HttpApi.HTTP_DATA_CHUNK dataChunk = default;
                        dataChunk.DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                        dataChunk.pBuffer       = (byte *)(pBuffer + offset);
                        dataChunk.BufferLength  = dataToWrite;

                        flags |= _leftToWrite == size ? Interop.HttpApi.HTTP_FLAGS.NONE : Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
                        if (!sentHeaders)
                        {
                            statusCode = _httpContext.Response.SendHeaders(&dataChunk, null, flags, false);
                        }
                        else
                        {
                            if (NetEventSource.Log.IsEnabled())
                            {
                                NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendResponseEntityBody");
                            }

                            statusCode =
                                Interop.HttpApi.HttpSendResponseEntityBody(
                                    _httpContext.RequestQueueHandle,
                                    _httpContext.RequestId,
                                    (uint)flags,
                                    1,
                                    &dataChunk,
                                    null,
                                    SafeLocalAllocHandle.Zero,
                                    0,
                                    null,
                                    null);

                            if (NetEventSource.Log.IsEnabled())
                            {
                                NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                            }
                            if (_httpContext.Listener !.IgnoreWriteExceptions)
                            {
                                if (NetEventSource.Log.IsEnabled())
                                {
                                    NetEventSource.Info(this, "Write() suppressing error");
                                }
                                statusCode = Interop.HttpApi.ERROR_SUCCESS;
                            }
                        }
                    }
                }
            }
            finally
            {
                // free unmanaged buffer
                bufferAsIntPtr?.Close();
            }

            if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_HANDLE_EOF)
            {
                Exception exception = new HttpListenerException((int)statusCode);
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(this, exception.ToString());
                }
                _closed = true;
                _httpContext.Abort();
                throw exception;
            }
            UpdateAfterWrite(dataToWrite);
            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.DumpBuffer(this, buffer, offset, (int)dataToWrite);
            }
        }
Exemple #3
0
        protected override void Dispose(bool disposing)
        {
            if (NetEventSource.IsEnabled) NetEventSource.Enter(this);

            try
            {
                if (disposing)
                {
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "_closed:" + _closed);
                    if (_closed)
                    {
                        if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
                        return;
                    }
                    _closed = true;
                    Interop.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
                    if (_leftToWrite > 0 && !_inOpaqueMode)
                    {
                        throw new InvalidOperationException(SR.net_io_notenoughbyteswritten);
                    }
                    bool sentHeaders = _httpContext.Response.SentHeaders;
                    if (sentHeaders && _leftToWrite == 0)
                    {
                        if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
                        return;
                    }

                    uint statusCode = 0;
                    if ((_httpContext.Response.BoundaryType == BoundaryType.Chunked || _httpContext.Response.BoundaryType == BoundaryType.None) && (String.Compare(_httpContext.Request.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase) != 0))
                    {
                        if (_httpContext.Response.BoundaryType == BoundaryType.None)
                        {
                            flags |= Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
                        }
                        fixed (void* pBuffer = ChunkTerminator)
                        {
                            Interop.HttpApi.HTTP_DATA_CHUNK* pDataChunk = null;
                            if (_httpContext.Response.BoundaryType == BoundaryType.Chunked)
                            {
                                Interop.HttpApi.HTTP_DATA_CHUNK dataChunk = new Interop.HttpApi.HTTP_DATA_CHUNK();
                                dataChunk.DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                                dataChunk.pBuffer = (byte*)pBuffer;
                                dataChunk.BufferLength = (uint)ChunkTerminator.Length;
                                pDataChunk = &dataChunk;
                            }
                            if (!sentHeaders)
                            {
                                statusCode = _httpContext.Response.SendHeaders(pDataChunk, null, flags, false);
                            }
                            else
                            {
                                if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendResponseEntityBody");

                                statusCode =
                                    Interop.HttpApi.HttpSendResponseEntityBody(
                                        _httpContext.RequestQueueHandle,
                                        _httpContext.RequestId,
                                        (uint)flags,
                                        pDataChunk != null ? (ushort)1 : (ushort)0,
                                        pDataChunk,
                                        null,
                                        SafeLocalAllocHandle.Zero,
                                        0,
                                        null,
                                        null);

                                if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                                if (_httpContext.Listener.IgnoreWriteExceptions)
                                {
                                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Suppressing error");
                                    statusCode = Interop.HttpApi.ERROR_SUCCESS;
                                }
                            }
                        }
                    }
                    else
                    {
                        if (!sentHeaders)
                        {
                            statusCode = _httpContext.Response.SendHeaders(null, null, flags, false);
                        }
                    }
                    if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_HANDLE_EOF)
                    {
                        Exception exception = new HttpListenerException((int)statusCode);
                        if (NetEventSource.IsEnabled) NetEventSource.Error(this, exception.ToString());
                        _httpContext.Abort();
                        throw exception;
                    }
                    _leftToWrite = 0;
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
            if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
        }
Exemple #4
0
        public override void Write(byte[] buffer, int offset, int size)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(this);
                NetEventSource.Info(this, "buffer.Length:" + buffer.Length + " size:" + size + " offset:" + offset);
            }
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }
            if (offset < 0 || offset > buffer.Length)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }
            if (size < 0 || size > buffer.Length - offset)
            {
                throw new ArgumentOutOfRangeException(nameof(size));
            }
            Interop.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (_closed || (size == 0 && _leftToWrite != 0))
            {
                if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
                return;
            }
            if (_leftToWrite >= 0 && size > _leftToWrite)
            {
                throw new ProtocolViolationException(SR.net_entitytoobig);
            }

            uint statusCode;
            uint dataToWrite = (uint)size;
            SafeLocalAllocHandle bufferAsIntPtr = null;
            IntPtr pBufferAsIntPtr = IntPtr.Zero;
            bool sentHeaders = _httpContext.Response.SentHeaders;
            try
            {
                if (size == 0)
                {
                    statusCode = _httpContext.Response.SendHeaders(null, null, flags, false);
                }
                else
                {
                    fixed (byte* pDataBuffer = buffer)
                    {
                        byte* pBuffer = pDataBuffer;
                        if (_httpContext.Response.BoundaryType == BoundaryType.Chunked)
                        {
                            string chunkHeader = size.ToString("x", CultureInfo.InvariantCulture);
                            dataToWrite = dataToWrite + (uint)(chunkHeader.Length + 4);
                            bufferAsIntPtr = SafeLocalAllocHandle.LocalAlloc((int)dataToWrite);
                            pBufferAsIntPtr = bufferAsIntPtr.DangerousGetHandle();
                            for (int i = 0; i < chunkHeader.Length; i++)
                            {
                                Marshal.WriteByte(pBufferAsIntPtr, i, (byte)chunkHeader[i]);
                            }
                            Marshal.WriteInt16(pBufferAsIntPtr, chunkHeader.Length, 0x0A0D);
                            Marshal.Copy(buffer, offset, pBufferAsIntPtr + chunkHeader.Length + 2, size);
                            Marshal.WriteInt16(pBufferAsIntPtr, (int)(dataToWrite - 2), 0x0A0D);
                            pBuffer = (byte*)pBufferAsIntPtr;
                            offset = 0;
                        }
                        Interop.HttpApi.HTTP_DATA_CHUNK dataChunk = new Interop.HttpApi.HTTP_DATA_CHUNK();
                        dataChunk.DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                        dataChunk.pBuffer = (byte*)(pBuffer + offset);
                        dataChunk.BufferLength = dataToWrite;

                        flags |= _leftToWrite == size ? Interop.HttpApi.HTTP_FLAGS.NONE : Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
                        if (!sentHeaders)
                        {
                            statusCode = _httpContext.Response.SendHeaders(&dataChunk, null, flags, false);
                        }
                        else
                        {
                            if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendResponseEntityBody");

                            statusCode =
                                Interop.HttpApi.HttpSendResponseEntityBody(
                                    _httpContext.RequestQueueHandle,
                                    _httpContext.RequestId,
                                    (uint)flags,
                                    1,
                                    &dataChunk,
                                    null,
                                    SafeLocalAllocHandle.Zero,
                                    0,
                                    null,
                                    null);

                            if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                            if (_httpContext.Listener.IgnoreWriteExceptions)
                            {
                                if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Write() suppressing error");
                                statusCode = Interop.HttpApi.ERROR_SUCCESS;
                            }
                        }
                    }
                }
            }
            finally
            {
                // free unmanaged buffer
                bufferAsIntPtr?.Close();
            }

            if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_HANDLE_EOF)
            {
                Exception exception = new HttpListenerException((int)statusCode);
                if (NetEventSource.IsEnabled) NetEventSource.Error(this, exception.ToString());
                _closed = true;
                _httpContext.Abort();
                throw exception;
            }
            UpdateAfterWrite(dataToWrite);
            if (NetEventSource.IsEnabled) NetEventSource.DumpBuffer(this, buffer, offset, (int)dataToWrite);
            if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
        }
        private void DisposeCore()
        {
            Interop.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite();
            if (_leftToWrite > 0 && !_inOpaqueMode)
            {
                throw new InvalidOperationException(SR.net_io_notenoughbyteswritten);
            }
            bool sentHeaders = _httpContext.Response.SentHeaders;

            if (sentHeaders && _leftToWrite == 0)
            {
                return;
            }

            uint statusCode = 0;

            if ((_httpContext.Response.BoundaryType == BoundaryType.Chunked || _httpContext.Response.BoundaryType == BoundaryType.None) && !string.Equals(_httpContext.Request.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase))
            {
                if (_httpContext.Response.BoundaryType == BoundaryType.None)
                {
                    flags |= Interop.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
                }

                fixed(void *pBuffer = &s_chunkTerminator[0])
                {
                    Interop.HttpApi.HTTP_DATA_CHUNK *pDataChunk = null;
                    if (_httpContext.Response.BoundaryType == BoundaryType.Chunked)
                    {
                        Interop.HttpApi.HTTP_DATA_CHUNK dataChunk = default;
                        dataChunk.DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                        dataChunk.pBuffer       = (byte *)pBuffer;
                        dataChunk.BufferLength  = (uint)s_chunkTerminator.Length;
                        pDataChunk = &dataChunk;
                    }
                    if (!sentHeaders)
                    {
                        statusCode = _httpContext.Response.SendHeaders(pDataChunk, null, flags, false);
                    }
                    else
                    {
                        if (NetEventSource.Log.IsEnabled())
                        {
                            NetEventSource.Info(this, "Calling Interop.HttpApi.HttpSendResponseEntityBody");
                        }

                        statusCode =
                            Interop.HttpApi.HttpSendResponseEntityBody(
                                _httpContext.RequestQueueHandle,
                                _httpContext.RequestId,
                                (uint)flags,
                                pDataChunk != null ? (ushort)1 : (ushort)0,
                                pDataChunk,
                                null,
                                SafeLocalAllocHandle.Zero,
                                0,
                                null,
                                null);

                        if (NetEventSource.Log.IsEnabled())
                        {
                            NetEventSource.Info(this, "Call to Interop.HttpApi.HttpSendResponseEntityBody returned:" + statusCode);
                        }
                        if (_httpContext.Listener.IgnoreWriteExceptions)
                        {
                            if (NetEventSource.Log.IsEnabled())
                            {
                                NetEventSource.Info(this, "Suppressing error");
                            }
                            statusCode = Interop.HttpApi.ERROR_SUCCESS;
                        }
                    }
                }
            }
            else
            {
                if (!sentHeaders)
                {
                    statusCode = _httpContext.Response.SendHeaders(null, null, flags, false);
                }
            }
            if (statusCode != Interop.HttpApi.ERROR_SUCCESS && statusCode != Interop.HttpApi.ERROR_HANDLE_EOF)
            {
                Exception exception = new HttpListenerException((int)statusCode);
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(this, exception.ToString());
                }
                _httpContext.Abort();
                throw exception;
            }
            _leftToWrite = 0;
        }
            private unsafe void UpdateDataChunk()
            {
                if (_dataChunks == null)
                {
                    _dataChunks = new Interop.HttpApi.HTTP_DATA_CHUNK[2];
                    _dataChunksGCHandle = GCHandle.Alloc(_dataChunks, GCHandleType.Pinned);
                    _dataChunks[0] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[0].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[1] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[1].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                }

                Debug.Assert(_buffer == null || _bufferList == null, "Either 'm_Buffer' or 'm_BufferList' MUST be NULL.");
                Debug.Assert(_shouldCloseOutput || _buffer != null || _bufferList != null, "Either 'm_Buffer' or 'm_BufferList' MUST NOT be NULL.");

                // The underlying byte[] m_Buffer or each m_BufferList[].Array are pinned already 
                if (_buffer != null)
                {
                    UpdateDataChunk(0, _buffer, _offset, _count);
                    UpdateDataChunk(1, null, 0, 0);
                    _dataChunkCount = 1;
                }
                else if (_bufferList != null)
                {
                    Debug.Assert(_bufferList != null && _bufferList.Count == 2,
                        "'m_BufferList' MUST NOT be NULL and have exactly '2' items at this point.");
                    UpdateDataChunk(0, _bufferList[0].Array, _bufferList[0].Offset, _bufferList[0].Count);
                    UpdateDataChunk(1, _bufferList[1].Array, _bufferList[1].Offset, _bufferList[1].Count);
                    _dataChunkCount = 2;
                }
                else
                {
                    Debug.Assert(_shouldCloseOutput, "'m_ShouldCloseOutput' MUST be 'true' at this point.");
                    _dataChunks = null;
                }
            }
        internal HttpResponseStreamAsyncResult(object asyncObject, object userState, AsyncCallback callback, byte[] buffer, int offset, int size, bool chunked, bool sentHeaders, ThreadPoolBoundHandle boundHandle) : base(asyncObject, userState, callback)
        {
            _boundHandle = boundHandle;
            _sentHeaders = sentHeaders;

            if (size == 0)
            {
                _dataChunks  = null;
                _pOverlapped = boundHandle.AllocateNativeOverlapped(s_IOCallback, state: this, pinData: null);
            }
            else
            {
                _dataChunks = new Interop.HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1];

                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Info(this, "m_pOverlapped:0x" + ((IntPtr)_pOverlapped).ToString("x8"));
                }

                object[] objectsToPin = new object[1 + _dataChunks.Length];
                objectsToPin[_dataChunks.Length] = _dataChunks;


                int    chunkHeaderOffset = 0;
                byte[] chunkHeaderBuffer = null;
                if (chunked)
                {
                    chunkHeaderBuffer = GetChunkHeader(size, out chunkHeaderOffset);

                    _dataChunks[0] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[0].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[0].BufferLength  = (uint)(chunkHeaderBuffer.Length - chunkHeaderOffset);

                    objectsToPin[0] = chunkHeaderBuffer;

                    _dataChunks[1] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[1].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[1].BufferLength  = (uint)size;

                    objectsToPin[1] = buffer;

                    _dataChunks[2] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[2].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[2].BufferLength  = (uint)s_CRLFArray.Length;

                    objectsToPin[2] = s_CRLFArray;
                }
                else
                {
                    _dataChunks[0] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[0].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[0].BufferLength  = (uint)size;

                    objectsToPin[0] = buffer;
                }

                // This call will pin needed memory
                _pOverlapped = boundHandle.AllocateNativeOverlapped(s_IOCallback, state: this, pinData: objectsToPin);

                if (chunked)
                {
                    _dataChunks[0].pBuffer = (byte *)(Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer, chunkHeaderOffset));
                    _dataChunks[1].pBuffer = (byte *)(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset));
                    _dataChunks[2].pBuffer = (byte *)(Marshal.UnsafeAddrOfPinnedArrayElement(s_CRLFArray, 0));
                }
                else
                {
                    _dataChunks[0].pBuffer = (byte *)(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset));
                }
            }
        }
        internal HttpResponseStreamAsyncResult(object asyncObject, object userState, AsyncCallback callback, byte[] buffer, int offset, int size, bool chunked, bool sentHeaders, ThreadPoolBoundHandle boundHandle) : base(asyncObject, userState, callback)
        {
            _boundHandle = boundHandle;
            _sentHeaders = sentHeaders;

            if (size == 0)
            {
                _dataChunks = null;
                _pOverlapped = boundHandle.AllocateNativeOverlapped(s_IOCallback, state: this, pinData: null);
            }
            else
            {
                _dataChunks = new Interop.HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1];

                if (NetEventSource.IsEnabled) NetEventSource.Info(this, "m_pOverlapped:0x" + ((IntPtr)_pOverlapped).ToString("x8"));

                object[] objectsToPin = new object[1 + _dataChunks.Length];
                objectsToPin[_dataChunks.Length] = _dataChunks;


                int chunkHeaderOffset = 0;
                byte[] chunkHeaderBuffer = null;
                if (chunked)
                {
                    chunkHeaderBuffer = GetChunkHeader(size, out chunkHeaderOffset);

                    _dataChunks[0] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[0].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[0].BufferLength = (uint)(chunkHeaderBuffer.Length - chunkHeaderOffset);

                    objectsToPin[0] = chunkHeaderBuffer;

                    _dataChunks[1] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[1].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[1].BufferLength = (uint)size;

                    objectsToPin[1] = buffer;

                    _dataChunks[2] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[2].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[2].BufferLength = (uint)s_CRLFArray.Length;

                    objectsToPin[2] = s_CRLFArray;
                }
                else
                {
                    _dataChunks[0] = new Interop.HttpApi.HTTP_DATA_CHUNK();
                    _dataChunks[0].DataChunkType = Interop.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[0].BufferLength = (uint)size;

                    objectsToPin[0] = buffer;
                }

                // This call will pin needed memory
                _pOverlapped = boundHandle.AllocateNativeOverlapped(s_IOCallback, state: this, pinData: objectsToPin);

                if (chunked)
                {
                    _dataChunks[0].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer, chunkHeaderOffset));
                    _dataChunks[1].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset));
                    _dataChunks[2].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(s_CRLFArray, 0));
                }
                else
                {
                    _dataChunks[0].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset));
                }
            }
        }