Example #1
0
        private async Task RunReaderAsync()
        {
            try
            {
                if (IsServer)
                {
                    EnsureBuffer(ClientPreface.Length);
                    await ClientPreface.ReadAsync(inputStream, config.ClientPrefaceTimeout);
                }

                var continueRead = true;

                if (serverUpgradeRequest != null)
                {
                    var upgrade = serverUpgradeRequest;
                    serverUpgradeRequest = null;

                    var headers = new CompleteHeadersFrameData
                    {
                        StreamId    = 1u,
                        Priority    = null,
                        Headers     = upgrade.Headers,
                        EndOfStream = upgrade.Payload == null,
                    };

                    var err = await HandleHeaders(headers);

                    if (err != null)
                    {
                        if (err.Value.StreamId == 0)
                        {
                            continueRead = false;
                        }
                        await HandleFrameProcessingError(err.Value);
                    }
                    else if (upgrade.Payload != null)
                    {
                        var buf = config.BufferPool.Rent(upgrade.Payload.Length);
                        Array.Copy(
                            upgrade.Payload, 0, buf, 0, upgrade.Payload.Length);

                        StreamImpl stream = null;
                        lock (shared.Mutex)
                        {
                            shared.streamMap.TryGetValue(1u, out stream);
                        }

                        bool tookBufferOwnership;
                        err = stream.PushBuffer(
                            new ArraySegment <byte>(buf, 0, upgrade.Payload.Length),
                            true,
                            out tookBufferOwnership);
                        if (!tookBufferOwnership)
                        {
                            config.BufferPool.Return(buf);
                        }
                        if (err != null)
                        {
                            if (err.Value.StreamId == 0)
                            {
                                continueRead = false;
                            }
                            await HandleFrameProcessingError(err.Value);
                        }
                    }
                }

                while (continueRead)
                {
                    EnsureBuffer(PersistentBufferSize);
                    var err = await ReadOneFrame();

                    ReleaseBuffer(PersistentBufferSize);
                    if (err != null)
                    {
                        if (err.Value.StreamId == 0)
                        {
                            continueRead = false;
                        }
                        await HandleFrameProcessingError(err.Value);
                    }
                }
            }
            catch (Exception e)
            {
            }

            await writer.CloseNow();

            await writer.Done;

            Dictionary <uint, StreamImpl> activeStreams = null;

            lock (shared.Mutex)
            {
                activeStreams    = shared.streamMap;
                shared.streamMap = null;


                shared.Closed = true;
            }
            foreach (var kvp in activeStreams)
            {
                await kvp.Value.Reset(ErrorCode.ConnectError, fromRemote : true);
            }

            PingState pingState = null;

            lock (shared.Mutex)
            {
                if (shared.PingState != null)
                {
                    pingState        = shared.PingState;
                    shared.PingState = null;
                }
            }
            if (pingState != null)
            {
                var ex = new ConnectionClosedException();
                foreach (var kvp in pingState.PingMap)
                {
                    kvp.Value.SetException(ex);
                }
            }
            if (!remoteGoAwayTcs.Task.IsCompleted)
            {
                remoteGoAwayTcs.TrySetException(new EndOfStreamException());
            }

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

            headerReader.Dispose();
        }
Example #2
0
        private async ValueTask <Http2Error?> HandleHeaders(CompleteHeadersFrameData headers)
        {
            if (headers.StreamId == 0)
            {
                return(new Http2Error
                {
                    StreamId = headers.StreamId,
                    Code = ErrorCode.ProtocolError,
                    Message = "Received HEADERS frame with stream ID 0",
                });
            }

            StreamImpl stream             = null;
            uint       lastOutgoingStream = 0u;
            uint       lastIncomingStream = 0u;

            lock (shared.Mutex)
            {
                lastIncomingStream = shared.LastIncomingStreamId;
                lastOutgoingStream = shared.LastOutgoingStreamId;
                shared.streamMap.TryGetValue(headers.StreamId, out stream);
            }

            if (stream != null)
            {
                if (headers.Priority.HasValue)
                {
                    var handlePrioErr = HandlePriorityData(
                        headers.StreamId, headers.Priority.Value);
                    if (handlePrioErr != null)
                    {
                        return(handlePrioErr);
                    }
                }
                return(stream.ProcessHeaders(headers));
            }

            var isServerInitiated = headers.StreamId % 2 == 0;
            var isRemoteInitiated =
                (IsServer && !isServerInitiated) || (!IsServer && isServerInitiated);

            var isValidNewStream =
                IsServer &&
                isRemoteInitiated &&
                (headers.StreamId > lastIncomingStream);


            if (!isValidNewStream)
            {
                return(new Http2Error
                {
                    StreamId = headers.StreamId,
                    Code = ErrorCode.StreamClosed,
                    Message = "拒绝不打开新流的头",
                });
            }

            lock (shared.Mutex)
            {
                shared.LastIncomingStreamId = headers.StreamId;

                if (shared.GoAwaySent)
                {
                    return(new Http2Error
                    {
                        StreamId = headers.StreamId,
                        Code = ErrorCode.RefusedStream,
                        Message = "离开",
                    });
                }

                if ((uint)shared.streamMap.Count + 1 > localSettings.MaxConcurrentStreams)
                {
                    return(new Http2Error
                    {
                        StreamId = headers.StreamId,
                        Code = ErrorCode.RefusedStream,
                        Message = "由于最大并发流而拒绝流",
                    });
                }
            }

            var newStream = new StreamImpl(
                this, headers.StreamId, StreamState.Idle,
                (int)localSettings.InitialWindowSize);

            lock (shared.Mutex)
            {
                shared.streamMap[headers.StreamId] = newStream;
            }

            if (!writer.RegisterStream(headers.StreamId))
            {
                return(new Http2Error
                {
                    StreamId = 0,
                    Code = ErrorCode.InternalError,
                    Message = "Can't register stream at writer",
                });
            }

            var err = newStream.ProcessHeaders(headers);

            if (err != null)
            {
                return(err);
            }

            if (headers.Priority.HasValue)
            {
                err = HandlePriorityData(
                    headers.StreamId,
                    headers.Priority.Value);
                if (err != null)
                {
                    return(err);
                }
            }

            var handledByUser = config.StreamListener(newStream);

            if (!handledByUser)
            {
                await newStream.Reset(ErrorCode.RefusedStream, false);
            }

            return(null);
        }
Example #3
0
        /// <summary>
        /// 处理传入头的接收
        /// </summary>
        public Http2Error?ProcessHeaders(
            CompleteHeadersFrameData headers)
        {
            var wakeupDataWaiter    = false;
            var wakeupHeaderWaiter  = false;
            var wakeupTrailerWaiter = false;
            var removeStream        = false;

            lock (stateMutex)
            {
                switch (state)
                {
                case StreamState.ReservedLocal:
                case StreamState.ReservedRemote:
                    return(new Http2Error
                    {
                        StreamId = Id,
                        Code = ErrorCode.InternalError,
                        Message = "接收到的头帧处于未覆盖的推送约定状态",
                    });

                case StreamState.Idle:
                case StreamState.Open:
                case StreamState.HalfClosedLocal:
                    if (headersReceived != HeaderReceptionState.ReceivedAllHeaders)
                    {
                        HeaderValidationResult hvr;
                        if (connection.IsServer)
                        {
                            hvr = HeaderValidator.ValidateRequestHeaders(headers.Headers);
                        }
                        else
                        {
                            hvr = HeaderValidator.ValidateResponseHeaders(headers.Headers);
                        }
                        if (hvr != HeaderValidationResult.Ok)
                        {
                            return(new Http2Error
                            {
                                StreamId = Id,
                                Code = ErrorCode.ProtocolError,
                                Message = "Received invalid headers",
                            });
                        }

                        if (!connection.config.IsServer &&
                            headers.Headers.IsInformationalHeaders())
                        {
                            headersReceived =
                                HeaderReceptionState.ReceivedInformationalHeaders;
                        }
                        else
                        {
                            headersReceived =
                                HeaderReceptionState.ReceivedAllHeaders;
                        }
                        wakeupHeaderWaiter      = true;
                        declaredInContentLength = headers.Headers.GetContentLength();
                        inHeaders = headers.Headers;
                    }
                    else if (!dataReceived)
                    {
                        return(new Http2Error
                        {
                            StreamId = Id,
                            Code = ErrorCode.ProtocolError,
                            Message = "接收的无标题",
                        });
                    }
                    else
                    {
                        if (!headers.EndOfStream)
                        {
                            return(new Http2Error
                            {
                                StreamId = Id,
                                Code = ErrorCode.ProtocolError,
                                Message = "接收到没有endofstream标志",
                            });
                        }
                        var hvr = HeaderValidator.ValidateTrailingHeaders(headers.Headers);
                        if (hvr != HeaderValidationResult.Ok)
                        {
                            return(new Http2Error
                            {
                                StreamId = Id,
                                Code = ErrorCode.ProtocolError,
                                Message = "接收到无效",
                            });
                        }


                        if (declaredInContentLength >= 0 &&
                            declaredInContentLength != totalInData)
                        {
                            return(new Http2Error
                            {
                                StreamId = Id,
                                Code = ErrorCode.ProtocolError,
                                Message =
                                    "数据帧的长度与内容长度不匹配",
                            });
                        }

                        wakeupTrailerWaiter = true;
                        inTrailers          = headers.Headers;
                    }

                    if (state == StreamState.Idle)
                    {
                        state = StreamState.Open;
                    }
                    if (headers.EndOfStream)
                    {
                        if (state == StreamState.HalfClosedLocal)
                        {
                            state        = StreamState.Closed;
                            removeStream = true;
                        }
                        else
                        {
                            state = StreamState.HalfClosedRemote;
                        }
                        wakeupTrailerWaiter = true;
                        wakeupDataWaiter    = true;
                    }
                    break;

                case StreamState.HalfClosedRemote:
                case StreamState.Closed:
                    return(new Http2Error
                    {
                        Code = ErrorCode.StreamClosed,
                        StreamId = Id,
                        Message = "已接收封闭流的头",
                    });

                case StreamState.Reset:
                    break;

                default:
                    throw new Exception("未处理的流状态");
                }
            }

            if (wakeupHeaderWaiter)
            {
                readHeadersPossible.Set();
            }
            if (wakeupDataWaiter)
            {
                readDataPossible.Set();
            }
            if (wakeupTrailerWaiter)
            {
                readTrailersPossible.Set();
            }

            if (removeStream)
            {
                connection.UnregisterStream(this);
            }

            return(null);
        }