internal ResponseStreamAsyncResult(ResponseStream responseStream, CancellationTokenRegistration cancellationRegistration)
 {
     _responseStream           = responseStream;
     _tcs                      = new TaskCompletionSource <object>();
     _cancellationRegistration = cancellationRegistration;
 }
        internal ResponseStreamAsyncResult(ResponseStream responseStream, BufferBuilder buffer, bool chunked,
                                           CancellationTokenRegistration cancellationRegistration)
            : this(responseStream, cancellationRegistration)
        {
            var boundHandle = _responseStream.RequestContext.Server.BoundHandle;

            object[] objectsToPin;

            if (buffer.TotalBytes == 0)
            {
                _dataChunks = null;
                _overlapped = new SafeNativeOverlapped(boundHandle,
                                                       boundHandle.AllocateNativeOverlapped(IOCallback, this, null));
                return;
            }

            _dataChunks     = new HttpApi.HTTP_DATA_CHUNK[buffer.BufferCount + (chunked ? 2 : 0)];
            objectsToPin    = new object[_dataChunks.Length + 1];
            objectsToPin[0] = _dataChunks;
            var currentChunk = 0;
            var currentPin   = 1;

            var chunkHeaderBuffer = new ArraySegment <byte>();

            if (chunked)
            {
                chunkHeaderBuffer = Helpers.GetChunkHeader(buffer.TotalBytes);
                SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, chunkHeaderBuffer);
            }

            foreach (var segment in buffer.Buffers)
            {
                SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, segment);
            }

            if (chunked)
            {
                SetDataChunk(_dataChunks, ref currentChunk, objectsToPin, ref currentPin, new ArraySegment <byte>(Helpers.CRLF));
            }

            // This call will pin needed memory
            _overlapped = new SafeNativeOverlapped(boundHandle,
                                                   boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin));

            currentChunk = 0;
            if (chunked)
            {
                _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer.Array, chunkHeaderBuffer.Offset);
                currentChunk++;
            }
            foreach (var segment in buffer.Buffers)
            {
                _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array, segment.Offset);
                currentChunk++;
            }
            if (chunked)
            {
                _dataChunks[currentChunk].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0);
                currentChunk++;
            }

            // We've captured a reference to all the buffers, clear the buffer so that it can be used to queue overlapped writes.
            buffer.Clear();
        }
        internal ResponseStreamAsyncResult(ResponseStream responseStream, string fileName, long offset,
                                           long?count, bool chunked, CancellationTokenRegistration cancellationRegistration)
            : this(responseStream, cancellationRegistration)
        {
            var boundHandle = responseStream.RequestContext.Server.BoundHandle;

            int bufferSize = 1024 * 64; // TODO: Validate buffer size choice.

#if NETSTANDARD1_3
            _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive.
#else
            // It's too expensive to validate anything before opening the file. Open the file and then check the lengths.
            _fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize,
                                         FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive.
#endif
            long length = _fileStream.Length;                                                    // Expensive
            if (offset < 0 || offset > length)
            {
                _fileStream.Dispose();
                throw new ArgumentOutOfRangeException("offset", offset, string.Empty);
            }
            if (count.HasValue && (count < 0 || count > length - offset))
            {
                _fileStream.Dispose();
                throw new ArgumentOutOfRangeException("count", count, string.Empty);
            }

            if (count == 0 || (!count.HasValue && _fileStream.Length == 0))
            {
                _dataChunks = null;
                _overlapped = new SafeNativeOverlapped(boundHandle,
                                                       boundHandle.AllocateNativeOverlapped(IOCallback, this, null));
            }
            else
            {
                _dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1];

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

                var chunkHeaderBuffer = new ArraySegment <byte>();
                if (chunked)
                {
                    chunkHeaderBuffer                      = Helpers.GetChunkHeader((int)(count ?? _fileStream.Length - offset));
                    _dataChunks[0].DataChunkType           = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count;
                    objectsToPin[0] = chunkHeaderBuffer.Array;

                    _dataChunks[1].DataChunkType       = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
                    _dataChunks[1].fromFile.offset     = (ulong)offset;
                    _dataChunks[1].fromFile.count      = (ulong)(count ?? -1);
                    _dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle();
                    // Nothing to pin for the file handle.

                    _dataChunks[2].DataChunkType           = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
                    _dataChunks[2].fromMemory.BufferLength = (uint)Helpers.CRLF.Length;
                    objectsToPin[1] = Helpers.CRLF;
                }
                else
                {
                    _dataChunks[0].DataChunkType       = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
                    _dataChunks[0].fromFile.offset     = (ulong)offset;
                    _dataChunks[0].fromFile.count      = (ulong)(count ?? -1);
                    _dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle();
                }

                // This call will pin needed memory
                _overlapped = new SafeNativeOverlapped(boundHandle,
                                                       boundHandle.AllocateNativeOverlapped(IOCallback, this, objectsToPin));

                if (chunked)
                {
                    // These must be set after pinning with Overlapped.
                    _dataChunks[0].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer.Array, chunkHeaderBuffer.Offset);
                    _dataChunks[2].fromMemory.pBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(Helpers.CRLF, 0);
                }
            }
        }