Пример #1
0
        internal async Task InitReadAsync(CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} INIT READ ASYNC");

            var buffer   = new BufferOffsetSize(new byte[4096], false);
            var state    = ReadState.None;
            int position = 0;

            while (true)
            {
                Operation.ThrowIfClosedOrDisposed(cancellationToken);

                WebConnection.Debug($"{ME} INIT READ ASYNC LOOP: {state} {position} - {buffer.Offset}/{buffer.Size}");

                var nread = await RequestStream.InnerStream.ReadAsync(
                    buffer.Buffer, buffer.Offset, buffer.Size, cancellationToken).ConfigureAwait(false);

                WebConnection.Debug($"{ME} INIT READ ASYNC LOOP #1: {state} {position} - {buffer.Offset}/{buffer.Size} - {nread}");

                if (nread == 0)
                {
                    throw GetReadException(WebExceptionStatus.ReceiveFailure, null, "ReadDoneAsync2");
                }

                if (nread < 0)
                {
                    throw GetReadException(WebExceptionStatus.ServerProtocolViolation, null, "ReadDoneAsync3");
                }

                buffer.Offset += nread;
                buffer.Size   -= nread;

                if (state == ReadState.None)
                {
                    try {
                        var oldPos = position;
                        if (!GetResponse(buffer, ref position, ref state))
                        {
                            position = oldPos;
                        }
                    } catch (Exception e) {
                        WebConnection.Debug($"{ME} INIT READ ASYNC FAILED: {e.Message}\n{e}");
                        throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, "ReadDoneAsync4");
                    }
                }

                if (state == ReadState.Aborted)
                {
                    throw GetReadException(WebExceptionStatus.RequestCanceled, null, "ReadDoneAsync5");
                }

                if (state == ReadState.Content)
                {
                    buffer.Size   = buffer.Offset - position;
                    buffer.Offset = position;
                    break;
                }

                int est = nread * 2;
                if (est > buffer.Size)
                {
                    var newBuffer = new byte [buffer.Buffer.Length + est];
                    Buffer.BlockCopy(buffer.Buffer, 0, newBuffer, 0, buffer.Offset);
                    buffer = new BufferOffsetSize(newBuffer, buffer.Offset, newBuffer.Length - buffer.Offset, false);
                }
                state    = ReadState.None;
                position = 0;
            }

            WebConnection.Debug($"{ME} INIT READ ASYNC LOOP DONE: {buffer.Offset} {buffer.Size}");

            try {
                Initialize(buffer);
            } catch (Exception e) {
                throw GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadDoneAsync6");
            }
        }
Пример #2
0
        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);
        }
Пример #3
0
        void Initialize(BufferOffsetSize buffer)
        {
            WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}");

            long   contentLength;
            string contentType = Headers["Transfer-Encoding"];
            bool   chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            string clength     = Headers["Content-Length"];

            if (!chunkedRead && !string.IsNullOrEmpty(clength))
            {
                if (!long.TryParse(clength, out contentLength))
                {
                    contentLength = Int64.MaxValue;
                }
            }
            else
            {
                contentLength = Int64.MaxValue;
            }

            string tencoding = null;

            if (ExpectContent)
            {
                tencoding = Headers["Transfer-Encoding"];
            }

            ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);

            if (Version == HttpVersion.Version11 && RequestStream.KeepAlive)
            {
                KeepAlive = true;
                var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"];
                if (cncHeader != null)
                {
                    cncHeader = cncHeader.ToLower();
                    KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1;
                    if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1)
                    {
                        KeepAlive = false;
                    }
                }

                if (!ChunkedRead && contentLength == Int64.MaxValue)
                {
                    /*
                     * This is a violation of the HTTP Spec - the server neither send a
                     * "Content-Length:" nor a "Transfer-Encoding: chunked" header.
                     * The only way to recover from this is to keep reading until the
                     * remote closes the connection, so we can't reuse it.
                     */
                    KeepAlive = false;
                }
            }

            /*
             * Inner layer:
             * We may have read a few extra bytes while parsing the headers, these will be
             * passed to us in the @buffer parameter and we need to read these before
             * reading from the `InnerStream`.
             */
            Stream networkStream;

            if (!ExpectContent || (!ChunkedRead && buffer.Size >= contentLength))
            {
                bufferedEntireContent = true;
                innerStream           = new BufferedReadStream(Operation, null, buffer);
                networkStream         = innerStream;
            }
            else if (buffer.Size > 0)
            {
                networkStream = new BufferedReadStream(Operation, RequestStream.InnerStream, buffer);
            }
            else
            {
                networkStream = RequestStream.InnerStream;
            }

            /*
             * Intermediate layer:
             * - Wrap with MonoChunkStream when using chunked encoding.
             * - Otherwise, we should have a Content-Length, wrap with
             *   FixedSizeReadStream to read exactly that many bytes.
             */
            if (ChunkedRead)
            {
                innerStream = new MonoChunkStream(Operation, networkStream, Headers);
            }
            else if (bufferedEntireContent)
            {
                // 'innerStream' has already been set above.
            }
            else if (contentLength != Int64.MaxValue)
            {
                innerStream = new FixedSizeReadStream(Operation, networkStream, contentLength);
            }
            else
            {
                // Violation of the HTTP Spec - neither chunked nor length.
                innerStream = new BufferedReadStream(Operation, networkStream, null);
            }

            /*
             * Outer layer:
             * - Decode gzip/deflate if requested.
             */
            string content_encoding = Headers["Content-Encoding"];

            if (content_encoding == "gzip" && (Request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
            {
                innerStream = ContentDecodeStream.Create(Operation, innerStream, ContentDecodeStream.Mode.GZip);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }
            else if (content_encoding == "deflate" && (Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
            {
                innerStream = ContentDecodeStream.Create(Operation, innerStream, ContentDecodeStream.Mode.Deflate);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }

            WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}");

            if (!ExpectContent)
            {
                nextReadCalled = true;
                Operation.Finish(true);
            }
        }
Пример #4
0
        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);
        }
Пример #6
0
 void Debug(string message)
 {
     WebConnection.Debug($"SPS({ID}): {message}");
 }
        async Task <(int, int)> ProcessRead(byte[] buffer, int offset, int size, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} PROCESS READ: {totalRead} {contentLength}");

            cancellationToken.ThrowIfCancellationRequested();
            if (totalRead >= contentLength)
            {
                read_eof      = true;
                contentLength = totalRead;
                return(0, 0);
            }

            int oldBytes  = 0;
            int remaining = readBuffer?.Size ?? 0;

            if (remaining > 0)
            {
                int copy = (remaining > size) ? size : remaining;
                Buffer.BlockCopy(readBuffer.Buffer, readBuffer.Offset, buffer, offset, copy);
                readBuffer.Offset += copy;
                readBuffer.Size   -= copy;
                offset            += copy;
                size      -= copy;
                totalRead += copy;
                if (totalRead >= contentLength)
                {
                    contentLength = totalRead;
                    read_eof      = true;
                }
                if (size == 0 || totalRead >= contentLength)
                {
                    return(0, copy);
                }
                oldBytes = copy;
            }

            if (contentLength != Int64.MaxValue && contentLength - totalRead < size)
            {
                size = (int)(contentLength - totalRead);
            }

            WebConnection.Debug($"{ME} PROCESS READ #1: {oldBytes} {size} {read_eof}");

            if (read_eof)
            {
                contentLength = totalRead;
                return(oldBytes, 0);
            }

            var ret = await InnerReadAsync(buffer, offset, size, cancellationToken).ConfigureAwait(false);

            if (ret <= 0)
            {
                read_eof      = true;
                contentLength = totalRead;
                return(oldBytes, 0);
            }

            totalRead += ret;
            return(oldBytes, ret);
        }
        async Task Initialize(BufferOffsetSize buffer, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}");

            string contentType = Headers["Transfer-Encoding"];
            bool   chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            string clength     = Headers["Content-Length"];

            if (!chunkedRead && !string.IsNullOrEmpty(clength))
            {
                if (!long.TryParse(clength, out contentLength))
                {
                    contentLength = Int64.MaxValue;
                }
            }
            else
            {
                contentLength = Int64.MaxValue;
            }

            if (Version == HttpVersion.Version11 && RequestStream.KeepAlive)
            {
                KeepAlive = true;
                var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"];
                if (cncHeader != null)
                {
                    cncHeader = cncHeader.ToLower();
                    KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1;
                    if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1)
                    {
                        KeepAlive = false;
                    }
                }
            }

            // Negative numbers?
            if (!Int32.TryParse(clength, out stream_length))
            {
                stream_length = -1;
            }

            string me        = "WebResponseStream.Initialize()";
            string tencoding = null;

            if (ExpectContent)
            {
                tencoding = Headers["Transfer-Encoding"];
            }

            ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            if (!ChunkedRead)
            {
                readBuffer = buffer;
                try {
                    if (contentLength > 0 && readBuffer.Size >= contentLength)
                    {
                        if (!IsNtlmAuth())
                        {
                            await ReadAllAsync(false, cancellationToken).ConfigureAwait(false);
                        }
                    }
                } catch (Exception e) {
                    throw GetReadException(WebExceptionStatus.ReceiveFailure, e, me);
                }
            }
            else if (ChunkStream == null)
            {
                try {
                    ChunkStream = new MonoChunkStream(buffer.Buffer, buffer.Offset, buffer.Offset + buffer.Size, Headers);
                } catch (Exception e) {
                    throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, me);
                }
            }
            else
            {
                ChunkStream.ResetBuffer();
                try {
                    ChunkStream.Write(buffer.Buffer, buffer.Offset, buffer.Size);
                } catch (Exception e) {
                    throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, me);
                }
            }

            WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}");

            if (!ExpectContent)
            {
                if (!closed && !nextReadCalled)
                {
                    if (contentLength == Int64.MaxValue)
                    {
                        contentLength = 0;
                    }
                    nextReadCalled = true;
                }
                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);
        }
Пример #10
0
 void Debug(string message, params object[] args)
 {
     WebConnection.Debug($"SPS({ID}): {string.Format (message, args)}");
 }
Пример #11
0
        void Initialize(BufferOffsetSize buffer)
        {
            WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}");

            string contentType = Headers["Transfer-Encoding"];
            bool   chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            string clength     = Headers["Content-Length"];

            if (!chunkedRead && !string.IsNullOrEmpty(clength))
            {
                if (!long.TryParse(clength, out contentLength))
                {
                    contentLength = Int64.MaxValue;
                }
            }
            else
            {
                contentLength = Int64.MaxValue;
            }

            if (Version == HttpVersion.Version11 && RequestStream.KeepAlive)
            {
                KeepAlive = true;
                var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"];
                if (cncHeader != null)
                {
                    cncHeader = cncHeader.ToLower();
                    KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1;
                    if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1)
                    {
                        KeepAlive = false;
                    }
                }
            }

            // Negative numbers?
            if (!Int32.TryParse(clength, out stream_length))
            {
                stream_length = -1;
            }

            string tencoding = null;

            if (ExpectContent)
            {
                tencoding = Headers["Transfer-Encoding"];
            }

            ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);

            if (ChunkedRead)
            {
                innerStreamWrapper = innerChunkStream = new MonoChunkStream(
                    Operation, CreateStreamWrapper(buffer), Headers);
            }
            else if (!IsNtlmAuth() && contentLength > 0 && buffer.Size >= contentLength)
            {
                innerStreamWrapper = new BufferedReadStream(Operation, null, buffer);
            }
            else
            {
                innerStreamWrapper = CreateStreamWrapper(buffer);
            }

            string content_encoding = Headers["Content-Encoding"];

            if (content_encoding == "gzip" && (Request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
            {
                innerStreamWrapper = new GZipStream(innerStreamWrapper, CompressionMode.Decompress);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }
            else if (content_encoding == "deflate" && (Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
            {
                innerStreamWrapper = new DeflateStream(innerStreamWrapper, CompressionMode.Decompress);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }

            WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}");

            if (!ExpectContent)
            {
                if (!closed && !nextReadCalled)
                {
                    if (contentLength == Int64.MaxValue)
                    {
                        contentLength = 0;
                    }
                    nextReadCalled = true;
                }
                Operation.CompleteResponseRead(true);
            }
        }
Пример #12
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);
        }
Пример #13
0
        public override async Task WriteAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} WRITE ASYNC: {buffer.Length}/{offset}/{size}");

            Operation.ThrowIfClosedOrDisposed(cancellationToken);

            if (Operation.WriteBuffer != null)
            {
                throw new InvalidOperationException();
            }

            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));
            }

            var myWriteTcs = new TaskCompletionSource <int> ();

            if (Interlocked.CompareExchange(ref pendingWrite, myWriteTcs, null) != null)
            {
                throw new InvalidOperationException(SR.GetString(SR.net_repcall));
            }

            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;
                myWriteTcs.TrySetResult(0);
            } 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;
                myWriteTcs.TrySetException(ex);
                throw;
            }
        }