From 53d246840db9b2ed23b1fd8f12649a6653f12c17 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 11 Oct 2025 15:48:05 +0800 Subject: [PATCH] http3: fix qlog encoding of frame_parsed and frame_created events (#5372) --- http3/qlog/event.go | 8 ++------ http3/qlog/event_test.go | 4 ++-- http3/qlog/frame.go | 10 ++++++---- http3/qlog/frame_test.go | 6 +++--- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/http3/qlog/event.go b/http3/qlog/event.go index d419376e..7fe1051c 100644 --- a/http3/qlog/event.go +++ b/http3/qlog/event.go @@ -50,8 +50,6 @@ func (e FrameParsed) Name() string { return "http3:frame_parsed" } func (e FrameParsed) Encode(enc *jsontext.Encoder, _ time.Time) error { h := encoderHelper{enc: enc} h.WriteToken(jsontext.BeginObject) - h.WriteToken(jsontext.String("name")) - h.WriteToken(jsontext.String("frame_parsed")) h.WriteToken(jsontext.String("stream_id")) h.WriteToken(jsontext.Uint(uint64(e.StreamID))) h.WriteToken(jsontext.String("raw")) @@ -59,7 +57,7 @@ func (e FrameParsed) Encode(enc *jsontext.Encoder, _ time.Time) error { return err } h.WriteToken(jsontext.String("frame")) - if err := e.Frame.Encode(enc); err != nil { + if err := e.Frame.encode(enc); err != nil { return err } h.WriteToken(jsontext.EndObject) @@ -77,8 +75,6 @@ func (e FrameCreated) Name() string { return "http3:frame_created" } func (e FrameCreated) Encode(enc *jsontext.Encoder, _ time.Time) error { h := encoderHelper{enc: enc} h.WriteToken(jsontext.BeginObject) - h.WriteToken(jsontext.String("name")) - h.WriteToken(jsontext.String("frame_created")) h.WriteToken(jsontext.String("stream_id")) h.WriteToken(jsontext.Uint(uint64(e.StreamID))) h.WriteToken(jsontext.String("raw")) @@ -86,7 +82,7 @@ func (e FrameCreated) Encode(enc *jsontext.Encoder, _ time.Time) error { return err } h.WriteToken(jsontext.String("frame")) - if err := e.Frame.Encode(enc); err != nil { + if err := e.Frame.encode(enc); err != nil { return err } h.WriteToken(jsontext.EndObject) diff --git a/http3/qlog/event_test.go b/http3/qlog/event_test.go index 8f7ba254..0cab9109 100644 --- a/http3/qlog/event_test.go +++ b/http3/qlog/event_test.go @@ -73,7 +73,7 @@ func TestFrameParsedEvent(t *testing.T) { require.Equal(t, "http3:frame_parsed", name) require.Equal(t, float64(4), ev["stream_id"]) - require.Equal(t, "frame_parsed", ev["name"]) + require.NotContains(t, ev, "name") require.Contains(t, ev, "frame") } @@ -93,6 +93,6 @@ func TestFrameCreatedEvent(t *testing.T) { require.Equal(t, "http3:frame_created", name) require.Equal(t, float64(8), ev["stream_id"]) - require.Equal(t, "frame_created", ev["name"]) + require.NotContains(t, ev, "name") require.Contains(t, ev, "frame") } diff --git a/http3/qlog/frame.go b/http3/qlog/frame.go index 8f8b9efa..a3a1fb5e 100644 --- a/http3/qlog/frame.go +++ b/http3/qlog/frame.go @@ -9,14 +9,16 @@ type Frame struct { Frame any } -func (f Frame) Encode(enc *jsontext.Encoder) error { +func (f Frame) encode(enc *jsontext.Encoder) error { switch frame := f.Frame.(type) { - case *DataFrame: + case DataFrame: return frame.encode(enc) - case *HeadersFrame: + case HeadersFrame: return frame.encode(enc) } - return nil + // This shouldn't happen if the code is correctly logging frames. + // Write a null token to produce valid JSON. + return enc.WriteToken(jsontext.Null) } // A DataFrame is a DATA frame diff --git a/http3/qlog/frame_test.go b/http3/qlog/frame_test.go index 977ee955..a3c9e6e9 100644 --- a/http3/qlog/frame_test.go +++ b/http3/qlog/frame_test.go @@ -13,7 +13,7 @@ import ( func check(t *testing.T, f any, expected map[string]any) { var buf bytes.Buffer enc := jsontext.NewEncoder(&buf) - require.NoError(t, (Frame{Frame: f}).Encode(enc)) + require.NoError(t, (Frame{Frame: f}).encode(enc)) data := buf.Bytes() require.True(t, json.Valid(data), "invalid JSON: %s", string(data)) checkEncoding(t, data, expected) @@ -51,13 +51,13 @@ func checkEncoding(t *testing.T, data []byte, expected map[string]any) { } func TestDataFrame(t *testing.T) { - check(t, &DataFrame{}, map[string]any{ + check(t, DataFrame{}, map[string]any{ "frame_type": "data", }) } func TestHeadersFrame(t *testing.T) { - check(t, &HeadersFrame{ + check(t, HeadersFrame{ HeaderFields: []HeaderField{ {Name: ":status", Value: "200"}, {Name: "content-type", Value: "application/json"},