Ejemplo n.º 1
0
        private State ReadBody(byte[] buffer, ref int offset, int size)
        {
            if (_chunkSize == 0)
            {
                return(State.BodyFinished);
            }

            int diff = size - offset;

            if (diff + _chunkRead > _chunkSize)
            {
                diff = _chunkSize - _chunkRead;
            }

            byte[] chunk = new byte[diff];
            Buffer.BlockCopy(buffer, offset, chunk, 0, diff);
            _chunks.Add(new Chunk(chunk));
            offset        += diff;
            _chunkRead    += diff;
            _totalWritten += diff;

            return((_chunkRead == _chunkSize) ? State.BodyFinished : State.Body);
        }
Ejemplo n.º 2
0
        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.CompleteResponseRead(true);
                }
                return;
            }

            var timeoutTask = Task.Delay(ReadTimeout);
            var myReadTcs   = new TaskCompletionSource <int> ();

            while (true)
            {
                /*
                 * 'readTcs' is set by ReadAsync().
                 */
                cancellationToken.ThrowIfCancellationRequested();
                var oldReadTcs = Interlocked.CompareExchange(ref readTcs, myReadTcs, null);
                if (oldReadTcs == null)
                {
                    break;
                }

                // ReadAsync() is in progress.
                var anyTask = await Task.WhenAny(oldReadTcs.Task, timeoutTask).ConfigureAwait(false);

                if (anyTask == timeoutTask)
                {
                    throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout);
                }
            }

            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;
                myReadTcs.TrySetResult(new_size);
            } catch (Exception ex) {
                WebConnection.Debug($"{ME} READ ALL ASYNC EX: {ex.Message}");
                myReadTcs.TrySetException(ex);
                throw;
            } finally {
                WebConnection.Debug($"{ME} READ ALL ASYNC #2");
                readTcs = null;
            }

            Operation.CompleteResponseRead(true);
        }
Ejemplo n.º 3
0
        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);
        }