コード例 #1
0
        public override async ValueTask <BucketBytes> ReadAsync(int requested = int.MaxValue)
        {
            switch (_state)
            {
            case DechunkState.Chunk:
            {
                var bb = await Inner.ReadAsync(Math.Min(requested, _chunkLeft)).ConfigureAwait(false);

                _chunkLeft -= bb.Length;
                if (_chunkLeft == 0)
                {
                    _state     = DechunkState.Term;
                    _chunkLeft = 2;         // CRLF
                }
                return(bb);
            }

            case DechunkState.Eof:
                return(BucketBytes.Eof);

            default:
                await Advance(true).ConfigureAwait(false);

                if (_state == DechunkState.Chunk)
                {
                    goto case DechunkState.Chunk;
                }
                else if (_state == DechunkState.Eof)
                {
                    goto case DechunkState.Eof;
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
        }
コード例 #2
0
        async ValueTask Advance(bool wait)
        {
            while (_state != DechunkState.Chunk && _state != DechunkState.Eof)
            {
                if (!wait)
                {
                    var bb = Inner.Peek();

                    if (bb.IsEmpty)
                    {
                        return;
                    }
                }

                switch (_state)
                {
                case DechunkState.Start:
                {
                    var(bb, eol) = await Inner.ReadUntilEolAsync(BucketEol.CRLF | BucketEol.LF).ConfigureAwait(false);

                    if (eol == BucketEol.CRLF || eol == BucketEol.LF)
                    {
                        if (bb.Length > eol.CharCount())
                        {
                            _chunkLeft = Convert.ToInt32(bb.ToASCIIString(eol), 16);
                        }
                        else
                        {
                            _chunkLeft = 0;
                        }
                        _state = _chunkLeft > 0 ? DechunkState.Chunk : (_noFin ? DechunkState.Eof : DechunkState.Fin);
                    }
                    else if (bb.IsEof)
                    {
                        throw new HttpBucketException($"Unexpected EOF in {Name} Bucket");
                    }
                    else
                    {
                        _state = DechunkState.Size;
                        _start = bb.ToArray();

                        if (_start.Length > 16 || _start.Any(x => !IsHexCharOrCR(x)))
                        {
                            throw new HttpBucketException($"Invalid chunk header in {Name} Bucket");
                        }
                    }
                }
                break;

                case DechunkState.Size:
                {
                    var(bb, eol) = await Inner.ReadUntilEolAsync(BucketEol.CRLF | BucketEol.LF).ConfigureAwait(false);

                    if (eol != BucketEol.None && eol != BucketEol.CRSplit)
                    {
                        bb = _start !.AppendBytes(bb);
                        // Strip final '\r' if any, before passing to ToInt32
                        _chunkLeft = Convert.ToInt32(bb.Trim(eol).ToASCIIString(), 16);
                        _state     = _chunkLeft > 0 ? DechunkState.Chunk : (_noFin ? DechunkState.Eof : DechunkState.Fin);
                    }
                    else if (bb.IsEof)
                    {
                        throw new HttpBucketException($"Unexpected EOF in {Name} Bucket");
                    }
                    else
                    {
                        _start = _start !.AppendBytes(bb);

                        if (_start.Length > 16 || _start.Any(x => !IsHexCharOrCR(x)))
                        {
                            throw new HttpBucketException($"Invalid chunk header in {Name} Bucket");
                        }
                    }
                }
                break;

                case DechunkState.Term:
                {
                    var bb = await Inner.ReadAsync(_chunkLeft).ConfigureAwait(false);

                    _chunkLeft -= bb.Length;

                    if (bb.IsEof)
                    {
                        throw new HttpBucketException($"Unexpected EOF in {Name} Bucket");
                    }

                    if (_chunkLeft == 0)
                    {
                        _state = DechunkState.Start;
                    }
                }
                break;

                case DechunkState.Fin:
                {
                    var bb = await Inner.ReadAsync(2).ConfigureAwait(false);

                    if (bb.Length == 2)
                    {
                        _state = DechunkState.Eof;
                    }
                    else if (bb.Length == 1)
                    {
                        _state = DechunkState.Fin2;
                    }
                    else
                    {
                        throw new HttpBucketException($"Unexpected EOF in {Name} Bucket");
                    }
                }
                break;

                case DechunkState.Fin2:
                {
                    var bb = await Inner.ReadAsync(1).ConfigureAwait(false);

                    if (bb.Length == 1)
                    {
                        _state = DechunkState.Eof;
                    }
                    else
                    {
                        throw new HttpBucketException($"Unexpected EOF in {Name} Bucket");
                    }
                }
                break;

                case DechunkState.Chunk:
                case DechunkState.Eof:
                    return;
                }
            }
        }