private async Task <int> ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken token) { if (count == 0) { return(0); } _state.PinReceiveBuffer(buffer); var ctr = token.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); _state.AsyncReadInProgress = true; try { lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryDataAvailable))); } } int bytesAvailable = await _state.LifecycleAwaitable; lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpReadData( _requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)Math.Min(bytesAvailable, count), IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReadData))); } } return(await _state.LifecycleAwaitable); } finally { _state.AsyncReadInProgress = false; ctr.Dispose(); } }
private Task <bool> InternalWriteEndDataAsync(CancellationToken token) { _state.TcsInternalWriteDataToRequestStream = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); lock (_state.Lock) { if (!Interop.WinHttp.WinHttpWriteData( _requestHandle, IntPtr.Zero, 0, IntPtr.Zero)) { _state.TcsInternalWriteDataToRequestStream.TrySetException( new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpWriteData)))); } } return(_state.TcsInternalWriteDataToRequestStream.Task); }
public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if ((long)offset + (long)count > (long)buffer.Length) { throw new ArgumentException("buffer"); } CheckDisposed(); uint bytesRead = 0; GCHandle pinnedHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); bool result = Interop.WinHttp.WinHttpReadData( _requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)count, out bytesRead); pinnedHandle.Free(); if (!result) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError()); } return((int)bytesRead); }
private Task <bool> InternalWriteDataAsync(byte[] buffer, int offset, int count, CancellationToken token) { Debug.Assert(count >= 0); if (count == 0) { return(Task.FromResult <bool>(true)); } // TODO (Issue 2505): replace with PinnableBufferCache. if (!_cachedSendPinnedBuffer.IsAllocated || _cachedSendPinnedBuffer.Target != buffer) { if (_cachedSendPinnedBuffer.IsAllocated) { _cachedSendPinnedBuffer.Free(); } _cachedSendPinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); } _state.TcsInternalWriteDataToRequestStream = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); lock (_state.Lock) { if (!Interop.WinHttp.WinHttpWriteData( _state.RequestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)count, IntPtr.Zero)) { _state.TcsInternalWriteDataToRequestStream.TrySetException( new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError())); } } // TODO: Issue #2165. Register callback on cancellation token to cancel WinHTTP operation. return(_state.TcsInternalWriteDataToRequestStream.Task); }
public override Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (count > buffer.Length - offset) { throw new ArgumentException(nameof(buffer)); } if (token.IsCancellationRequested) { return(Task.FromCanceled <int>(token)); } CheckDisposed(); if (_state.TcsReadFromResponseStream != null && !_state.TcsReadFromResponseStream.Task.IsCompleted) { throw new InvalidOperationException(SR.net_http_no_concurrent_io_allowed); } // TODO (Issue 2505): replace with PinnableBufferCache. if (!_cachedReceivePinnedBuffer.IsAllocated || _cachedReceivePinnedBuffer.Target != buffer) { if (_cachedReceivePinnedBuffer.IsAllocated) { _cachedReceivePinnedBuffer.Free(); } _cachedReceivePinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); } _state.TcsReadFromResponseStream = new TaskCompletionSource <int>(TaskCreationOptions.RunContinuationsAsynchronously); _state.TcsQueryDataAvailable = new TaskCompletionSource <int>(TaskCreationOptions.RunContinuationsAsynchronously); _state.TcsQueryDataAvailable.Task.ContinueWith((previousTask) => { if (previousTask.IsFaulted) { _state.TcsReadFromResponseStream.TrySetException(previousTask.Exception.InnerException); } else if (previousTask.IsCanceled || token.IsCancellationRequested) { _state.TcsReadFromResponseStream.TrySetCanceled(token); } else { int bytesToRead; int bytesAvailable = previousTask.Result; if (bytesAvailable > count) { bytesToRead = count; } else { bytesToRead = bytesAvailable; } lock (_state.Lock) { if (!Interop.WinHttp.WinHttpReadData( _state.RequestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)bytesToRead, IntPtr.Zero)) { _state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError())); } } } }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); // TODO: Issue #2165. Register callback on cancellation token to cancel WinHTTP operation. lock (_state.Lock) { if (!Interop.WinHttp.WinHttpQueryDataAvailable(_state.RequestHandle, IntPtr.Zero)) { _state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError())); } } return(_state.TcsReadFromResponseStream.Task); }
public override Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (count > buffer.Length - offset) { throw new ArgumentException("buffer"); } if (token.IsCancellationRequested) { return(Task.FromCanceled <int>(token)); } CheckDisposed(); if (_state.TcsReadFromResponseStream != null && !_state.TcsReadFromResponseStream.Task.IsCompleted) { throw new InvalidOperationException(SR.net_http_no_concurrent_io_allowed); } // TODO (Issue 2505): replace with PinnableBufferCache. if (!_cachedReceivePinnedBuffer.IsAllocated || _cachedReceivePinnedBuffer.Target != buffer) { if (_cachedReceivePinnedBuffer.IsAllocated) { _cachedReceivePinnedBuffer.Free(); } _cachedReceivePinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); } _state.TcsReadFromResponseStream = new TaskCompletionSource <int>(); lock (_state.Lock) { if (!Interop.WinHttp.WinHttpReadData( _state.RequestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)count, IntPtr.Zero)) { _state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError())); } } // TODO: Issue #2165. Register callback on cancellation token to cancel WinHTTP operation. return(_state.TcsReadFromResponseStream.Task); }
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (count > buffer.Length - offset) { throw new ArgumentException(SR.net_http_buffer_insufficient_length, nameof(buffer)); } if (token.IsCancellationRequested) { return Task.FromCanceled<int>(token); } CheckDisposed(); if (_state.TcsReadFromResponseStream != null && !_state.TcsReadFromResponseStream.Task.IsCompleted) { throw new InvalidOperationException(SR.net_http_no_concurrent_io_allowed); } _state.PinReceiveBuffer(buffer); _state.TcsReadFromResponseStream = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); _state.TcsQueryDataAvailable = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); _state.TcsQueryDataAvailable.Task.ContinueWith((previousTask) => { if (previousTask.IsFaulted) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetException(previousTask.Exception.InnerException); } else if (previousTask.IsCanceled || token.IsCancellationRequested) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetCanceled(token); } else { int bytesToRead; int bytesAvailable = previousTask.Result; if (bytesAvailable > count) { bytesToRead = count; } else { bytesToRead = bytesAvailable; } lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpReadData( _requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset), (uint)bytesToRead, IntPtr.Zero)) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError().InitializeStackTrace())); } } } }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); // Register callback on cancellation token to cancel any pending WinHTTP operation. if (token.CanBeCanceled) { WinHttpTraceHelper.Trace("WinHttpResponseStream.ReadAsync: registering for cancellation token request"); _state.CtrReadFromResponseStream = token.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); } else { WinHttpTraceHelper.Trace("WinHttpResponseStream.ReadAsync: received no cancellation token"); } lock (_state.Lock) { Debug.Assert(!_requestHandle.IsInvalid); if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero)) { _state.DisposeCtrReadFromResponseStream(); _state.TcsReadFromResponseStream.TrySetException( new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError().InitializeStackTrace())); } } return _state.TcsReadFromResponseStream.Task; }
private async Task CopyToAsyncCore(Stream destination, byte[] buffer, CancellationToken cancellationToken) { _state.PinReceiveBuffer(buffer); CancellationTokenRegistration ctr = cancellationToken.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this); _state.AsyncReadInProgress = true; try { // Loop until there's no more data to be read while (true) { // Query for data available lock (_state.Lock) { if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryDataAvailable))); } } int bytesAvailable = await _state.LifecycleAwaitable; if (bytesAvailable == 0) { ReadResponseTrailers(); break; } Debug.Assert(bytesAvailable > 0); // Read the available data cancellationToken.ThrowIfCancellationRequested(); lock (_state.Lock) { if (!Interop.WinHttp.WinHttpReadData(_requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0), (uint)Math.Min(bytesAvailable, buffer.Length), IntPtr.Zero)) { throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReadData))); } } int bytesRead = await _state.LifecycleAwaitable; if (bytesRead == 0) { ReadResponseTrailers(); break; } Debug.Assert(bytesRead > 0); // Write that data out to the output stream #if NETSTANDARD2_1 await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false); #else await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); #endif } } finally { _state.AsyncReadInProgress = false; ctr.Dispose(); ArrayPool <byte> .Shared.Return(buffer); } // Leaving buffer pinned as it is in ReadAsync. It'll get unpinned when another read // request is made with a different buffer or when the state is cleared. }