Esempio n. 1
0
 public ValueTask <WriteResult> WriteWindowUpdate(
     FrameHeader header, WindowUpdateData data)
 {
     return(PerformWriteRequestAsync(
                header.StreamId,
                wr => {
         wr.Header = header;
         wr.WindowUpdateData = data;
     },
                false));
 }
        public static async Task AssertWindowUpdate(
            this IReadableByteStream stream,
            uint expectedStreamId,
            int increment)
        {
            var header = await stream.ReadFrameHeaderWithTimeout();

            Assert.Equal(FrameType.WindowUpdate, header.Type);
            Assert.Equal(WindowUpdateData.Size, header.Length);
            Assert.Equal(0, header.Flags);
            Assert.Equal(expectedStreamId, header.StreamId);
            var buf = new byte[WindowUpdateData.Size];
            await stream.ReadAllWithTimeout(new ArraySegment <byte>(buf));

            var wu = WindowUpdateData.DecodeFrom(new ArraySegment <byte>(buf));

            Assert.Equal(increment, wu.WindowSizeIncrement);
        }
        public static async Task WriteWindowUpdate(
            this IWriteAndCloseableByteStream stream, uint streamId, int amount)
        {
            var windowUpdateHeader = new FrameHeader
            {
                Type     = FrameType.WindowUpdate,
                Flags    = 0,
                Length   = WindowUpdateData.Size,
                StreamId = streamId,
            };
            var data = new WindowUpdateData
            {
                WindowSizeIncrement = amount,
            };
            var dataBytes = new byte[WindowUpdateData.Size];

            data.EncodeInto(new ArraySegment <byte>(dataBytes));
            await stream.WriteFrameHeader(windowUpdateHeader);

            await stream.WriteAsync(new ArraySegment <byte>(dataBytes));
        }
Esempio n. 4
0
        private async ValueTask <Http2Error?> HandleWindowUpdateFrame(FrameHeader fh)
        {
            if (fh.Length != WindowUpdateData.Size)
            {
                return(new Http2Error
                {
                    StreamId = 0,
                    Code = ErrorCode.FrameSizeError,
                    Message = "收到无效的窗口更新帧头",
                });
            }

            await inputStream.ReadAll(
                new ArraySegment <byte>(receiveBuffer, 0, WindowUpdateData.Size));

            var windowUpdateData = WindowUpdateData.DecodeFrom(
                new ArraySegment <byte>(receiveBuffer, 0, WindowUpdateData.Size));

            bool isIdleStream = false;

            lock (shared.Mutex)
            {
                isIdleStream = IsIdleStreamId(
                    fh.StreamId, shared.LastOutgoingStreamId, shared.LastIncomingStreamId);
            }

            if (isIdleStream)
            {
                return(new Http2Error
                {
                    StreamId = 0u,
                    Code = ErrorCode.ProtocolError,
                    Message = "接收到空闲流的窗口更新",
                });
            }

            return(writer.UpdateFlowControlWindow(
                       fh.StreamId, windowUpdateData.WindowSizeIncrement));
        }
Esempio n. 5
0
        private async ValueTask <object> SendWindowUpdate(int amount)
        {
            var fh = new FrameHeader
            {
                StreamId = this.Id,
                Type     = FrameType.WindowUpdate,
                Flags    = 0,
            };

            var updateData = new WindowUpdateData
            {
                WindowSizeIncrement = amount,
            };

            try
            {
                await this.connection.writer.WriteWindowUpdate(fh, updateData);
            }
            catch (Exception)
            {
            }

            return(null);
        }
Esempio n. 6
0
        private async ValueTask <Http2Error?> HandleDataFrame(FrameHeader fh)
        {
            if (fh.StreamId == 0)
            {
                return(new Http2Error
                {
                    StreamId = 0,
                    Code = ErrorCode.ProtocolError,
                    Message = "接收到无效的数据帧头",
                });
            }
            if ((fh.Flags & (byte)DataFrameFlags.Padded) != 0 &&
                fh.Length < 1)
            {
                return(new Http2Error
                {
                    StreamId = 0,
                    Code = ErrorCode.ProtocolError,
                    Message = "帧太小,无法包含填充",
                });
            }
            if (fh.Length > localSettings.MaxFrameSize)
            {
                return(new Http2Error
                {
                    StreamId = 0,
                    Code = ErrorCode.FrameSizeError,
                    Message = "超过最大帧大小",
                });
            }

            var dataBuffer = config.BufferPool.Rent(fh.Length);

            try
            {
                await inputStream.ReadAll(
                    new ArraySegment <byte>(dataBuffer, 0, fh.Length));
            }
            catch (Exception)
            {
                config.BufferPool.Return(dataBuffer);
                throw;
            }

            var isPadded = (fh.Flags & (byte)DataFrameFlags.Padded) != 0;
            var padLen   = 0;
            var offset   = isPadded ? 1 : 0;
            var dataSize = fh.Length;

            if (isPadded)
            {
                padLen   = dataBuffer[0];
                dataSize = fh.Length - 1 - padLen;
                if (dataSize < 0)
                {
                    config.BufferPool.Return(dataBuffer);
                    return(new Http2Error
                    {
                        StreamId = 0,
                        Code = ErrorCode.ProtocolError,
                        Message = "减法填充后帧太小",
                    });
                }
            }

            if (dataSize != 0)
            {
                if (dataSize > connReceiveFlowWindow)
                {
                    config.BufferPool.Return(dataBuffer);
                    return(new Http2Error
                    {
                        StreamId = 0,
                        Code = ErrorCode.FlowControlError,
                        Message = "超过接收窗口",
                    });
                }
                connReceiveFlowWindow -= dataSize;
            }

            StreamImpl stream = null;
            uint       lastIncomingStreamId;
            uint       lastOutgoingStreamId;

            lock (shared.Mutex)
            {
                lastIncomingStreamId = shared.LastIncomingStreamId;
                lastOutgoingStreamId = shared.LastOutgoingStreamId;
                shared.streamMap.TryGetValue(fh.StreamId, out stream);
            }

            Http2Error?processError = null;
            bool       streamTookBufferOwnership = false;

            if (stream != null)
            {
                processError = stream.PushBuffer(
                    new ArraySegment <byte>(dataBuffer, offset, dataSize),
                    (fh.Flags & (byte)DataFrameFlags.EndOfStream) != 0,
                    out streamTookBufferOwnership);
            }
            else
            {
                var isIdleStreamId = IsIdleStreamId(
                    fh.StreamId, lastOutgoingStreamId, lastIncomingStreamId);
                processError = new Http2Error
                {
                    StreamId = isIdleStreamId ? 0u : fh.StreamId,
                    Code     = ErrorCode.StreamClosed,
                    Message  = "接收到未知帧的数据",
                };
            }

            if (!streamTookBufferOwnership)
            {
                config.BufferPool.Return(dataBuffer);
            }
            dataBuffer = null;

            if (processError.HasValue && processError.Value.StreamId == 0)
            {
                return(processError);
            }

            var maxWindow            = Constants.InitialConnectionWindowSize;
            var possibleWindowUpdate = maxWindow - connReceiveFlowWindow;
            var windowUpdateAmount   = 0;

            if (possibleWindowUpdate >= (maxWindow / 2))
            {
                windowUpdateAmount     = possibleWindowUpdate;
                connReceiveFlowWindow += windowUpdateAmount;
            }

            if (windowUpdateAmount > 0)
            {
                var wfh = new FrameHeader
                {
                    StreamId = 0,
                    Type     = FrameType.WindowUpdate,
                    Flags    = 0,
                };

                var updateData = new WindowUpdateData
                {
                    WindowSizeIncrement = windowUpdateAmount,
                };

                try
                {
                    await writer.WriteWindowUpdate(wfh, updateData);
                }
                catch (Exception)
                {
                }
            }

            return(processError);
        }