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
        /// <summary>
        /// 在双向流的顶部创建新的HTTP/2连接
        /// </summary>
        /// <param name="config"></param>
        /// <param name="inputStream"></param>
        /// <param name="outputStream"></param>
        /// <param name="options"></param>
        public Connection(ConnectionConfiguration config, IReadableByteStream inputStream, IWriteAndCloseableByteStream outputStream, Options?options = null)
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }
            this.config = config;

            if (!config.IsServer)
            {
                clientState = new ClientState();
            }

            localSettings = config.Settings;

            localSettings.EnablePush = false;


            if (IsServer && options?.ServerUpgradeRequest != null)
            {
                serverUpgradeRequest = options.Value.ServerUpgradeRequest;
                if (!serverUpgradeRequest.IsValid)
                {
                    throw new ArgumentException(
                              "ServerUpgradeRequest无效.\n" +
                              "无效的HTTP/1升级请求必须被拒绝");
                }
                else
                {
                    remoteSettings = serverUpgradeRequest.Settings;
                }
            }

            if (inputStream == null)
            {
                throw new ArgumentNullException(nameof(inputStream));
            }
            if (outputStream == null)
            {
                throw new ArgumentNullException(nameof(outputStream));
            }
            this.inputStream = inputStream;


            shared.Mutex                = new object();
            shared.streamMap            = new Dictionary <uint, StreamImpl>();
            shared.LastOutgoingStreamId = 0u;
            shared.LastIncomingStreamId = 0u;
            shared.GoAwaySent           = false;
            shared.Closed               = false;
            shared.PingState            = null;


            if (!IsServer && options?.ClientUpgradeRequest != null)
            {
                var upgrade = options.Value.ClientUpgradeRequest;
                if (!upgrade.IsValid)
                {
                    throw new ArgumentException(
                              "ClientUpgradeRequest无效。\n" +
                              "无效的升级请求必须被HTTP/1处理程序拒绝");
                }

                localSettings = upgrade.Settings;

                var newStream = new StreamImpl(
                    this,
                    1u,
                    StreamState.HalfClosedLocal,
                    (int)localSettings.InitialWindowSize);

                shared.streamMap[1u]        = newStream;
                shared.LastOutgoingStreamId = 1u;
                var setStream =
                    upgrade.UpgradeRequestStreamTcs.TrySetResult(newStream);
            }

            var dynTableSizeLimit = Math.Min(localSettings.HeaderTableSize, int.MaxValue);

            writer = new ConnectionWriter(
                this, outputStream,
                new ConnectionWriter.Options
            {
                MaxFrameSize          = (int)remoteSettings.MaxFrameSize,
                MaxHeaderListSize     = (int)remoteSettings.MaxHeaderListSize,
                InitialWindowSize     = (int)remoteSettings.InitialWindowSize,
                DynamicTableSizeLimit = (int)dynTableSizeLimit,
            },
                new HPack.Encoder.Options
            {
                DynamicTableSize = (int)remoteSettings.HeaderTableSize,
                HuffmanStrategy  = config.HuffmanStrategy,
            }
                );

            nrUnackedSettings++;

            headerReader = new HeaderReader(
                new HPack.Decoder(new HPack.Decoder.Options
            {
                DynamicTableSizeLimit = (int)dynTableSizeLimit,
                BufferPool            = config.BufferPool,
            }),
                localSettings.MaxFrameSize,
                localSettings.MaxHeaderListSize,
                inputStream
                );

            readerDone = Task.Run(() => this.RunReaderAsync());
        }