예제 #1
0
 Task <int> ProcessRead(byte[] buffer, int offset, int size, CancellationToken cancellationToken)
 {
     if (read_eof)
     {
         return(Task.FromResult(0));
     }
     if (cancellationToken.IsCancellationRequested)
     {
         return(Task.FromCanceled <int> (cancellationToken));
     }
     return(HttpWebRequest.RunWithTimeout(
                ct => innerStream.ReadAsync(buffer, offset, size, ct),
                ReadTimeout,
                () => {
         Operation.Abort();
         innerStream.Dispose();
     }, cancellationToken));
 }
        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);
        }
예제 #3
0
        public override async Task <int> ReadAsync(byte[] buffer, int offset, int size, 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 (size < 0 || (length - offset) < size)
            {
                throw new ArgumentOutOfRangeException(nameof(size));
            }

            if (Interlocked.CompareExchange(ref nestedRead, 1, 0) != 0)
            {
                throw new InvalidOperationException("Invalid nested call.");
            }

            var myReadTcs = new TaskCompletionSource <int> ();

            while (!cancellationToken.IsCancellationRequested)
            {
                /*
                 * 'readTcs' is set by ReadAllAsync().
                 */
                var oldReadTcs = Interlocked.CompareExchange(ref readTcs, myReadTcs, null);
                WebConnection.Debug($"{ME} READ ASYNC #1: {oldReadTcs != null}");
                if (oldReadTcs == null)
                {
                    break;
                }
                await oldReadTcs.Task.ConfigureAwait(false);
            }

            WebConnection.Debug($"{ME} READ ASYNC #2: {totalRead} {contentLength}");

            int       nbytes  = 0;
            Exception throwMe = null;

            try {
                // FIXME: NetworkStream.ReadAsync() does not support cancellation.
                nbytes = await HttpWebRequest.RunWithTimeout(
                    ct => ProcessRead(buffer, offset, size, ct),
                    ReadTimeout, () => {
                    Operation.Abort();
                    InnerStream.Dispose();
                }).ConfigureAwait(false);
            } catch (Exception e) {
                throwMe = GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadAsync");
            }

            WebConnection.Debug($"{ME} READ ASYNC #3: {totalRead} {contentLength} - {nbytes} {throwMe?.Message}");

            if (throwMe != null)
            {
                lock (locker) {
                    myReadTcs.TrySetException(throwMe);
                    readTcs    = null;
                    nestedRead = 0;
                }

                closed = true;
                Operation.CompleteResponseRead(false, throwMe);
                throw throwMe;
            }

            lock (locker) {
                readTcs.TrySetResult(nbytes);
                readTcs    = null;
                nestedRead = 0;
            }

            if (totalRead >= contentLength && !nextReadCalled)
            {
                WebConnection.Debug($"{ME} READ ASYNC - READ COMPLETE: {nbytes} - {totalRead} {contentLength} {nextReadCalled}");
                if (!nextReadCalled)
                {
                    nextReadCalled = true;
                    Operation.CompleteResponseRead(true);
                }
            }

            return(nbytes);
        }