async Task WriteAsyncInner(byte[] buffer, int offset, int size, WebCompletionSource completion, CancellationToken cancellationToken) { try { await ProcessWrite(buffer, offset, size, cancellationToken).ConfigureAwait(false); WebConnection.Debug($"{ME} WRITE ASYNC #1: {allowBuffering} {sendChunked} {Request.ContentLength} {totalWritten}"); if (Request.ContentLength > 0 && totalWritten == Request.ContentLength) { await FinishWriting(cancellationToken); } pendingWrite = null; completion.TrySetCompleted(); } catch (Exception ex) { KillBuffer(); closed = true; WebConnection.Debug($"{ME} WRITE ASYNC EX: {ex.Message}"); if (ex is SocketException) { ex = new IOException("Error writing request", ex); } Operation.CompleteRequestWritten(this, ex); pendingWrite = null; completion.TrySetException(ex); throw; } }
public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { WebConnection.Debug($"{ME} READ ASYNC"); cancellationToken.ThrowIfCancellationRequested(); if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } int length = buffer.Length; if (offset < 0 || length < offset) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0 || (length - offset) < count) { throw new ArgumentOutOfRangeException(nameof(count)); } if (Interlocked.CompareExchange(ref nestedRead, 1, 0) != 0) { throw new InvalidOperationException("Invalid nested call."); } var completion = new WebCompletionSource(); while (!cancellationToken.IsCancellationRequested) { /* * 'currentRead' is set by ReadAllAsync(). */ var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null); WebConnection.Debug($"{ME} READ ASYNC #1: {oldCompletion != null}"); if (oldCompletion == null) { break; } await oldCompletion.WaitForCompletion().ConfigureAwait(false); } WebConnection.Debug($"{ME} READ ASYNC #2"); int nbytes = 0; Exception throwMe = null; try { nbytes = await ProcessRead(buffer, offset, count, cancellationToken).ConfigureAwait(false); } catch (Exception e) { throwMe = GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadAsync"); } WebConnection.Debug($"{ME} READ ASYNC #3: {nbytes} {throwMe?.Message}"); if (throwMe != null) { lock (locker) { completion.TrySetException(throwMe); pendingRead = null; nestedRead = 0; } closed = true; Operation.Finish(false, throwMe); throw throwMe; } lock (locker) { completion.TrySetCompleted(); pendingRead = null; nestedRead = 0; } if (nbytes <= 0 && !read_eof) { read_eof = true; if (!nextReadCalled) { WebConnection.Debug($"{ME} READ ASYNC - READ COMPLETE: {nbytes} - {nextReadCalled}"); if (!nextReadCalled) { nextReadCalled = true; Operation.Finish(true); } } } return(nbytes); }
internal async Task ReadAllAsync(bool resending, CancellationToken cancellationToken) { WebConnection.Debug($"{ME} READ ALL ASYNC: resending={resending} eof={read_eof} " + "nextReadCalled={nextReadCalled}"); if (read_eof || bufferedEntireContent || nextReadCalled) { if (!nextReadCalled) { nextReadCalled = true; Operation.Finish(true); } return; } var completion = new WebCompletionSource(); var timeoutCts = new CancellationTokenSource(); try { var timeoutTask = Task.Delay(ReadTimeout, timeoutCts.Token); while (true) { /* * 'currentRead' is set by ReadAsync(). */ cancellationToken.ThrowIfCancellationRequested(); var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null); if (oldCompletion == null) { break; } // ReadAsync() is in progress. var oldReadTask = oldCompletion.WaitForCompletion(); var anyTask = await Task.WhenAny(oldReadTask, timeoutTask).ConfigureAwait(false); if (anyTask == timeoutTask) { throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout); } } } finally { timeoutCts.Cancel(); timeoutCts.Dispose(); } WebConnection.Debug($"{ME} READ ALL ASYNC #1"); try { cancellationToken.ThrowIfCancellationRequested(); /* * We may have awaited on the 'readTcs', so check * for eof again as ReadAsync() may have set it. */ if (read_eof || bufferedEntireContent) { return; } /* * Simplify: if we're resending on a new connection, * then we can simply close the connection here. */ if (resending && !KeepAlive) { Close(); return; } var buffer = await ReadAllAsyncInner(cancellationToken).ConfigureAwait(false); var bos = new BufferOffsetSize(buffer, 0, buffer.Length, false); innerStream = new BufferedReadStream(Operation, null, bos); nextReadCalled = true; completion.TrySetCompleted(); } catch (Exception ex) { WebConnection.Debug($"{ME} READ ALL ASYNC EX: {ex.Message}"); completion.TrySetException(ex); throw; } finally { WebConnection.Debug($"{ME} READ ALL ASYNC #2"); pendingRead = null; } Operation.Finish(true); }
internal async Task ReadAllAsync(bool resending, CancellationToken cancellationToken) { WebConnection.Debug($"{ME} READ ALL ASYNC: resending={resending} eof={read_eof} total={totalRead} " + "length={contentLength} nextReadCalled={nextReadCalled}"); if (read_eof || totalRead >= contentLength || nextReadCalled) { if (!nextReadCalled) { nextReadCalled = true; Operation.Finish(true); } return; } var completion = new WebCompletionSource(); var timeoutCts = new CancellationTokenSource(); try { var timeoutTask = Task.Delay(ReadTimeout, timeoutCts.Token); while (true) { /* * 'currentRead' is set by ReadAsync(). */ cancellationToken.ThrowIfCancellationRequested(); var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null); if (oldCompletion == null) { break; } // ReadAsync() is in progress. var oldReadTask = oldCompletion.WaitForCompletion(); var anyTask = await Task.WhenAny(oldReadTask, timeoutTask).ConfigureAwait(false); if (anyTask == timeoutTask) { throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout); } } } finally { timeoutCts.Cancel(); timeoutCts.Dispose(); } WebConnection.Debug($"{ME} READ ALL ASYNC #1"); cancellationToken.ThrowIfCancellationRequested(); try { if (totalRead >= contentLength) { return; } byte[] b = null; int new_size; if (contentLength == Int64.MaxValue && !ChunkedRead) { WebConnection.Debug($"{ME} READ ALL ASYNC - NEITHER LENGTH NOR CHUNKED"); /* * This is a violation of the HTTP Spec - the server neither send a * "Content-Length:" nor a "Transfer-Encoding: chunked" header. * * When we're redirecting or resending for NTLM, then we can simply close * the connection here. * * However, if it's the final reply, then we need to try our best to read it. */ if (resending) { Close(); return; } KeepAlive = false; } if (contentLength == Int64.MaxValue) { MemoryStream ms = new MemoryStream(); BufferOffsetSize buffer = null; if (readBuffer != null && readBuffer.Size > 0) { ms.Write(readBuffer.Buffer, readBuffer.Offset, readBuffer.Size); readBuffer.Offset = 0; readBuffer.Size = readBuffer.Buffer.Length; if (readBuffer.Buffer.Length >= 8192) { buffer = readBuffer; } } if (buffer == null) { buffer = new BufferOffsetSize(new byte[8192], false); } int read; while ((read = await InnerReadAsync(buffer.Buffer, buffer.Offset, buffer.Size, cancellationToken)) != 0) { ms.Write(buffer.Buffer, buffer.Offset, read); } new_size = (int)ms.Length; contentLength = new_size; readBuffer = new BufferOffsetSize(ms.GetBuffer(), 0, new_size, false); } else { new_size = (int)(contentLength - totalRead); b = new byte[new_size]; int readSize = 0; if (readBuffer != null && readBuffer.Size > 0) { readSize = readBuffer.Size; if (readSize > new_size) { readSize = new_size; } Buffer.BlockCopy(readBuffer.Buffer, readBuffer.Offset, b, 0, readSize); } int remaining = new_size - readSize; int r = -1; while (remaining > 0 && r != 0) { r = await InnerReadAsync(b, readSize, remaining, cancellationToken); remaining -= r; readSize += r; } } readBuffer = new BufferOffsetSize(b, 0, new_size, false); totalRead = 0; nextReadCalled = true; completion.TrySetCompleted(); } catch (Exception ex) { WebConnection.Debug($"{ME} READ ALL ASYNC EX: {ex.Message}"); completion.TrySetException(ex); throw; } finally { WebConnection.Debug($"{ME} READ ALL ASYNC #2"); pendingRead = null; } Operation.Finish(true); }
public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { WebConnection.Debug($"{ME} READ ASYNC"); cancellationToken.ThrowIfCancellationRequested(); if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } int length = buffer.Length; if (offset < 0 || length < offset) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count < 0 || (length - offset) < count) { throw new ArgumentOutOfRangeException(nameof(count)); } if (Interlocked.CompareExchange(ref nestedRead, 1, 0) != 0) { throw new InvalidOperationException("Invalid nested call."); } var completion = new WebCompletionSource(); while (!cancellationToken.IsCancellationRequested) { /* * 'currentRead' is set by ReadAllAsync(). */ var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null); WebConnection.Debug($"{ME} READ ASYNC #1: {oldCompletion != null}"); if (oldCompletion == null) { break; } await oldCompletion.WaitForCompletion().ConfigureAwait(false); } WebConnection.Debug($"{ME} READ ASYNC #2: {totalRead} {contentLength}"); int oldBytes = 0, nbytes = 0; Exception throwMe = null; try { // FIXME: NetworkStream.ReadAsync() does not support cancellation. (oldBytes, nbytes) = await HttpWebRequest.RunWithTimeout( ct => ProcessRead(buffer, offset, count, ct), ReadTimeout, () => { Operation.Abort(); InnerStream.Dispose(); }, () => Operation.Aborted, cancellationToken).ConfigureAwait(false); } catch (Exception e) { throwMe = GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadAsync"); } WebConnection.Debug($"{ME} READ ASYNC #3: {totalRead} {contentLength} - {oldBytes} {nbytes} {throwMe?.Message}"); if (throwMe != null) { lock (locker) { completion.TrySetException(throwMe); pendingRead = null; nestedRead = 0; } closed = true; Operation.Finish(false, throwMe); throw throwMe; } lock (locker) { pendingRead.TrySetCompleted(); pendingRead = null; nestedRead = 0; } if (totalRead >= contentLength && !nextReadCalled) { WebConnection.Debug($"{ME} READ ASYNC - READ COMPLETE: {oldBytes} {nbytes} - {totalRead} {contentLength} {nextReadCalled}"); if (!nextReadCalled) { nextReadCalled = true; Operation.Finish(true); } } return(oldBytes + nbytes); }