Skip to content

Commit

Permalink
performance: use first h2 frame header detect instead of read first f…
Browse files Browse the repository at this point in the history
…rame from whole payload (#705)
  • Loading branch information
yuweizzz authored Dec 27, 2024
1 parent b01cb60 commit 252f1c2
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 15 deletions.
15 changes: 9 additions & 6 deletions pkg/event_processor/http2_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ import (
"golang.org/x/net/http2/hpack"
)

const H2Magic = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
const H2MagicLen = len(H2Magic)
const ClientPrefaceLen = len(http2.ClientPreface)

type HTTP2Request struct {
framer *http2.Framer
Expand All @@ -40,9 +39,13 @@ type HTTP2Request struct {
}

func (h2r *HTTP2Request) detect(payload []byte) error {
data := string(payload[0:H2MagicLen])
if data != H2Magic {
return errors.New("Not match http2 magic")
payloadLen := len(payload)
if payloadLen < ClientPrefaceLen {
return errors.New("Payload less than http2 ClientPreface")
}
data := string(payload[0:ClientPrefaceLen])
if data != http2.ClientPreface {
return errors.New("Not match http2 ClientPreface")
}
return nil
}
Expand Down Expand Up @@ -83,7 +86,7 @@ func (h2r *HTTP2Request) IsDone() bool {
}

func (h2r *HTTP2Request) Display() []byte {
_, err := h2r.bufReader.Discard(H2MagicLen)
_, err := h2r.bufReader.Discard(ClientPrefaceLen)
if err != nil {
log.Println("[http2 request] Discard HTTP2 Magic error:", err)
return h2r.reader.Bytes()
Expand Down
2 changes: 1 addition & 1 deletion pkg/event_processor/http2_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestHttp2RequestParser(t *testing.T) {
}
t.Logf("TestHttp2RequestParser: wrot body:%d", i)

_, err = h2r.bufReader.Discard(H2MagicLen)
_, err = h2r.bufReader.Discard(ClientPrefaceLen)
if err != nil {
t.Logf("[http2 request] Discard HTTP2 Magic error:%v", err)
}
Expand Down
55 changes: 47 additions & 8 deletions pkg/event_processor/http2_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"bufio"
"bytes"
"compress/gzip"
"errors"
"fmt"
"io"
"log"
Expand All @@ -26,6 +27,22 @@ import (
"golang.org/x/net/http2/hpack"
)

const frameHeaderLen = 9

// http2.FrameType
// const (
// FrameData FrameType = 0x0
// FrameHeaders FrameType = 0x1
// FramePriority FrameType = 0x2
// FrameRSTStream FrameType = 0x3
// FrameSettings FrameType = 0x4
// FramePushPromise FrameType = 0x5
// FramePing FrameType = 0x6
// FrameGoAway FrameType = 0x7
// FrameWindowUpdate FrameType = 0x8
// FrameContinuation FrameType = 0x9
// )

type HTTP2Response struct {
framer *http2.Framer
packerType PacketType
Expand All @@ -36,15 +53,37 @@ type HTTP2Response struct {
}

func (h2r *HTTP2Response) detect(payload []byte) error {
rd := bytes.NewReader(payload)
buf := bufio.NewReader(rd)
framer := http2.NewFramer(nil, buf)
framer.ReadMetaHeaders = hpack.NewDecoder(0, nil)
_, err := framer.ReadFrame()
if err != nil {
return err
payloadLen := len(payload)
if payloadLen < frameHeaderLen {
return errors.New("Payload less than http2 frame Header")
}
// https://httpwg.org/specs/rfc7540.html#FrameHeader
// All frames begin with a fixed 9-octet header followed by a variable-length payload.
//
// +-----------------------------------------------+
// | Length (24) |
// +---------------+---------------+---------------+
// | Type (8) | Flags (8) |
// +-+-------------+---------------+-------------------------------+
// |R| Stream Identifier (31) |
// +=+=============================================================+
// | Frame Payload (0...) ...
// +---------------------------------------------------------------+
data := payload[0:frameHeaderLen]
// currentFrameLen := uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
currentFrameType := http2.FrameType(data[3])
// Frame type in http2.FrameType
if currentFrameType > http2.FrameContinuation {
return errors.New("Invalid frame type")
}
// R: A reserved 1-bit field.
// The semantics of this bit are undefined, and the bit MUST remain unset (0x0) when
// sending and MUST be ignored when receiving.
reservedBit := uint32(data[5]) >> 7
if reservedBit == 0 {
return nil
}
return nil
return errors.New("Invalid reserved bit in frame header")
}

func (h2r *HTTP2Response) Init() {
Expand Down

0 comments on commit 252f1c2

Please sign in to comment.