/// <summary> /// リクエストフレームを入力 /// </summary> /// <param name="frame">リクエストフレーム</param> public void HandleRequest(IHttp2Frame frame) { lock (this.streams) { Debug.WriteLine($"Request : {frame.ToString()}"); if (frame.Header.StreamID == 0) { this.requestControlStreamReader.HandleFrame(frame); } else { if (frame is Http2RstStreamFrame rstFrame && (rstFrame.ErrorCode == Http2ErrorCode.Cancel || rstFrame.ErrorCode == Http2ErrorCode.RefusedStream)) { // PushPromise で予約した ID に対するキャンセル RFC7540 8.2.2 if (this.pushPromises.TryRemove(frame.Header.StreamID, out _)) { return; } } if (!this.streams.ContainsKey(frame.Header.StreamID)) { this.AddStreamReader(frame); } this.streams[frame.Header.StreamID].HandleRequest(frame); } } }
public static void AssertEqualsAndRelease(IHttp2Frame expected, IHttp2Frame actual) { try { Assert.Equal(expected, actual); } finally { ReferenceCountUtil.Release(expected); ReferenceCountUtil.Release(actual); // Will return -1 when not implements ReferenceCounted. Assert.True(RefCnt(expected) <= 0); Assert.True(RefCnt(actual) <= 0); } }
/// <summary> /// レスポンスフレームを入力 /// </summary> /// <param name="frame">レスポンスフレーム</param> public void HandleResponse(IHttp2Frame frame) { lock (this.streams) { Debug.WriteLine($"Response: {frame.ToString()}"); if (frame.Header.StreamID == 0) { this.responseControlStreamReader.HandleFrame(frame); } else { if (!this.streams.ContainsKey(frame.Header.StreamID)) { this.AddStreamReader(frame); } this.streams[frame.Header.StreamID].HandleResponse(frame); } } }
/// <summary> /// ストリームリストに新規の <see cref="Http2StreamReader"/> を追加 /// </summary> /// <param name="frame">フレーム</param> private void AddStreamReader(IHttp2Frame frame) { Http2StreamReader reader; if (this.pushPromises.TryRemove(frame.Header.StreamID, out var request)) { this.HttpRequestSent?.Invoke(request); // PUSH_PROMISE による予約済みストリーム reader = new Http2StreamReader(frame.Header.StreamID, this.requestHpackDecoder, this.responseHpackDecoder, this.maxCaptureSize, request); } else { // 通常のストリーム reader = new Http2StreamReader(frame.Header.StreamID, this.requestHpackDecoder, this.responseHpackDecoder, this.maxCaptureSize); } reader.PushPromise += this.OnPushPromise; reader.HttpRequestSent += this.OnHttpRequestSent; reader.HttpResponseSent += this.OnHttpResponseSent; reader.ClientWebSocketMessageSent += this.OnClientWebSocketMessageSent; reader.ServerWebSocketMessageSent += this.OnServerWebSocketMessageSent; reader.Reset += this.OnResetStream; this.streams.TryAdd(frame.Header.StreamID, reader); }
/// <summary> /// フレームを入力 /// </summary> /// <param name="frame">入力するフレーム</param> public void HandleFrame(IHttp2Frame frame) { lock (this.lockObject) { if (frame.Header.StreamID != 0) { return; } this.Frames.Add(frame); if (frame is Http2SettingsFrame settingsFrame && settingsFrame.IsAck) { IReadOnlyList <(Http2SettingKey Key, uint Value)> settings = default; // ACK が前後しても大丈夫なようにする if (settingsFrame.IsAck) { settings = this.Partner.Frames .OfType <Http2SettingsFrame>() .Where(x => !x.IsAck) .LastOrDefault() ?.Settings; } else if (this.Frames.OfType <Http2SettingsFrame>().Count(x => !x.IsAck) == this.Frames.OfType <Http2SettingsFrame>().Count(x => x.IsAck)) { settings = settingsFrame.Settings; } if (settings?.Any(x => x.Key == Http2SettingKey.HeaderTableSize) ?? false) { var size = settings.First(x => x.Key == Http2SettingKey.HeaderTableSize).Value; this.UpdateDynamicTableSize?.Invoke(size); } } } }
public static bool HasFlag(this IHttp2Frame frame, byte flag) => (frame.Header.Flags & flag) == flag;
/// <summary> /// ペイロードデータから HTTP/2 フレームを作成 /// </summary> /// <param name="payload"></param> /// <returns></returns> public IHttp2Frame CreateFrame(byte[] payload) { if (payload.Length != this.Length) { throw new ArgumentException("Invalid Length."); } IHttp2Frame frame = null; switch (this.Type) { case Http2FrameType.Data: frame = new Http2DataFrame(this, payload); break; case Http2FrameType.Headers: frame = new Http2HeadersFrame(this, payload); break; case Http2FrameType.Priority: frame = new Http2PriorityFrame(this, payload); break; case Http2FrameType.RstStream: frame = new Http2RstStreamFrame(this, payload); break; case Http2FrameType.Settings: frame = new Http2SettingsFrame(this, payload); break; case Http2FrameType.PushPromise: frame = new Http2PushPromiseFrame(this, payload); break; case Http2FrameType.Ping: frame = new Http2PingFrame(this, payload); break; case Http2FrameType.Goaway: frame = new Http2GoawayFrame(this, payload); break; case Http2FrameType.WindowUpdate: frame = new Http2WindowUpdateFrame(this, payload); break; case Http2FrameType.Continuation: frame = new Http2ContinuationFrame(this, payload); break; case Http2FrameType.Altsvc: frame = new Http2AltsvcFrame(this, payload); break; case Http2FrameType.Origin: frame = new Http2OriginFrame(this, payload); break; default: frame = new Http2UnknownFrame(this, payload); break; } return(frame); }