public async Task ServerShouldCloseTheConnectionIfCorrectPrefaceIsNotReceived()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, inPipe, outPipe);

            var b = new byte[ClientPreface.Length];

            // Initialize with non-preface data
            for (var i = 0; i < b.Length; i++)
            {
                b[i] = 10;
            }
            await inPipe.WriteAsync(new ArraySegment <byte>(b));

            // Wait for the response - a settings frame is expected first
            // But as there's a race condition the connection could be closed
            // before or after the settings frame was fully received
            try
            {
                await outPipe.ReadAndDiscardSettings();

                var hdrBuf = new byte[FrameHeader.HeaderSize + 50];
                var header = await FrameHeader.ReceiveAsync(outPipe, hdrBuf);

                Assert.Equal(FrameType.GoAway, header.Type);
            }
            catch (Exception e)
            {
                Assert.IsType <System.IO.EndOfStreamException>(e);
            }
        }
        public static async Task <FrameHeader> ReadFrameHeaderWithTimeout(
            this IReadableByteStream stream)
        {
            var headerSpace = new byte[FrameHeader.HeaderSize];
            var readTask    = FrameHeader.ReceiveAsync(stream, headerSpace).AsTask();
            var timeoutTask = Task.Delay(5000);
            var combined    = Task.WhenAny(new Task[] { readTask, timeoutTask });
            var done        = await combined;

            if (done == readTask)
            {
                return(readTask.Result);
            }
            throw new TimeoutException();
        }
Example #3
0
        private async ValueTask <Http2Error?> ReadOneFrame()
        {
            var fh = await FrameHeader.ReceiveAsync(inputStream, receiveBuffer);

            if (!settingsReceived)
            {
                if (fh.Type != FrameType.Settings || (fh.Flags & (byte)SettingsFrameFlags.Ack) != 0)
                {
                    return(new Http2Error
                    {
                        StreamId = 0,
                        Code = ErrorCode.ProtocolError,
                        Message = "预期设置帧为第一帧",
                    });
                }
            }

            switch (fh.Type)
            {
            case FrameType.Settings:
                return(await HandleSettingsFrame(fh));

            case FrameType.Priority:
                return(await HandlePriorityFrame(fh));

            case FrameType.Ping:
                return(await HandlePingFrame(fh));

            case FrameType.WindowUpdate:
                return(await HandleWindowUpdateFrame(fh));

            case FrameType.PushPromise:
                return(await HandlePushPromiseFrame(fh));

            case FrameType.ResetStream:
                return(await HandleResetFrame(fh));

            case FrameType.GoAway:
                return(await HandleGoAwayFrame(fh));

            case FrameType.Continuation:
                return(new Http2Error
                {
                    StreamId = 0,
                    Code = ErrorCode.ProtocolError,
                    Message = "意外的继续帧",
                });

            case FrameType.Data:
                return(await HandleDataFrame(fh));

            case FrameType.Headers:
                var headerRes = await headerReader.ReadHeaders(fh, GetBuffer);

                if (headerRes.Error != null)
                {
                    return(headerRes.Error);
                }
                return(await HandleHeaders(headerRes.HeaderData));

            default:
                return(await HandleUnknownFrame(fh));
            }
        }
Example #4
0
        /// <summary>
        /// 读取和解码包含单个头段帧和0个或多个连续帧的头段块。
        /// </summary>
        /// <param name="firstHeader"></param>
        /// <param name="ensureBuffer"></param>
        /// <returns></returns>
        public async ValueTask <Result> ReadHeaders(
            FrameHeader firstHeader,
            Func <int, byte[]> ensureBuffer)
        {
            if (firstHeader.Length > maxFrameSize)
            {
                return(new Result
                {
                    Error = new Http2Error
                    {
                        StreamId = 0,
                        Code = ErrorCode.FrameSizeError,
                        Message = "超过最大帧大小",
                    },
                });
            }

            PriorityData?prioData           = null;
            var          allowedHeadersSize = maxHeaderFieldsSize;
            var          headers            = new List <HeaderField>();
            var          initialFlags       = firstHeader.Flags;

            var f              = (HeadersFrameFlags)firstHeader.Flags;
            var isEndOfStream  = f.HasFlag(HeadersFrameFlags.EndOfStream);
            var isEndOfHeaders = f.HasFlag(HeadersFrameFlags.EndOfHeaders);
            var isPadded       = f.HasFlag(HeadersFrameFlags.Padded);
            var hasPriority    = f.HasFlag(HeadersFrameFlags.Priority);


            var minLength = 0;

            if (isPadded)
            {
                minLength += 1;
            }
            if (hasPriority)
            {
                minLength += 5;
            }
            if (firstHeader.Length < minLength)
            {
                return(new Result
                {
                    Error = new Http2Error
                    {
                        StreamId = 0,
                        Code = ErrorCode.ProtocolError,
                        Message = "帧内容大小无效",
                    },
                });
            }

            byte[] buffer = ensureBuffer(firstHeader.Length);

            await reader.ReadAll(new ArraySegment <byte>(buffer, 0, firstHeader.Length));

            var offset = 0;
            var padLen = 0;

            if (isPadded)
            {
                padLen = buffer[0];
                offset++;
            }

            if (hasPriority)
            {
                prioData = PriorityData.DecodeFrom(
                    new ArraySegment <byte>(buffer, offset, 5));
                offset += 5;
            }

            var contentLen = firstHeader.Length - offset - padLen;

            if (contentLen < 0)
            {
                return(new Result
                {
                    Error = new Http2Error
                    {
                        StreamId = 0,
                        Code = ErrorCode.ProtocolError,
                        Message = "帧内容大小无效",
                    },
                });
            }


            hpackDecoder.AllowTableSizeUpdates = true;

            var decodeResult = hpackDecoder.DecodeHeaderBlockFragment(
                new ArraySegment <byte>(buffer, offset, contentLen),
                allowedHeadersSize,
                headers);

            var err = DecodeResultToError(decodeResult);

            if (err != null)
            {
                return(new Result {
                    Error = err
                });
            }

            allowedHeadersSize -= decodeResult.HeaderFieldsSize;

            while (!isEndOfHeaders)
            {
                var contHeader = await FrameHeader.ReceiveAsync(reader, buffer);

                if (contHeader.Type != FrameType.Continuation ||
                    contHeader.StreamId != firstHeader.StreamId ||
                    contHeader.Length > maxFrameSize ||
                    contHeader.Length == 0)
                {
                    return(new Result
                    {
                        Error = new Http2Error
                        {
                            StreamId = 0,
                            Code = ErrorCode.ProtocolError,
                            Message = "延续帧无效",
                        },
                    });
                }

                var contFlags = ((ContinuationFrameFlags)contHeader.Flags);
                isEndOfHeaders = contFlags.HasFlag(ContinuationFrameFlags.EndOfHeaders);


                buffer = ensureBuffer(contHeader.Length);
                await reader.ReadAll(new ArraySegment <byte>(buffer, 0, contHeader.Length));

                offset     = 0;
                contentLen = contHeader.Length;


                decodeResult = hpackDecoder.DecodeHeaderBlockFragment(
                    new ArraySegment <byte>(buffer, offset, contentLen),
                    allowedHeadersSize,
                    headers);

                var err2 = DecodeResultToError(decodeResult);
                if (err2 != null)
                {
                    return(new Result {
                        Error = err2
                    });
                }

                allowedHeadersSize -= decodeResult.HeaderFieldsSize;
            }


            if (!hpackDecoder.HasInitialState)
            {
                return(new Result
                {
                    Error = new Http2Error
                    {
                        Code = ErrorCode.CompressionError,
                        StreamId = 0u,
                        Message = "接收到不完整的头块",
                    },
                });
            }

            return(new Result
            {
                Error = null,
                HeaderData = new CompleteHeadersFrameData
                {
                    StreamId = firstHeader.StreamId,
                    Headers = headers,
                    Priority = prioData,
                    EndOfStream = isEndOfStream,
                },
            });
        }