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(); }
/// <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()); }