Skip to content

Commit c3e7b92

Browse files
committed
performance: use first h2 frame header detect instead of read first frame from whole payload
1 parent 848c8d9 commit c3e7b92

File tree

3 files changed

+57
-15
lines changed

3 files changed

+57
-15
lines changed

pkg/event_processor/http2_request.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ import (
2727
"golang.org/x/net/http2/hpack"
2828
)
2929

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

3332
type HTTP2Request struct {
3433
framer *http2.Framer
@@ -40,9 +39,13 @@ type HTTP2Request struct {
4039
}
4140

4241
func (h2r *HTTP2Request) detect(payload []byte) error {
43-
data := string(payload[0:H2MagicLen])
44-
if data != H2Magic {
45-
return errors.New("Not match http2 magic")
42+
payloadLen := len(payload)
43+
if payloadLen < ClientPrefaceLen {
44+
return errors.New("Payload less than http2 ClientPreface")
45+
}
46+
data := string(payload[0:ClientPrefaceLen])
47+
if data != http2.ClientPreface {
48+
return errors.New("Not match http2 ClientPreface")
4649
}
4750
return nil
4851
}
@@ -83,7 +86,7 @@ func (h2r *HTTP2Request) IsDone() bool {
8386
}
8487

8588
func (h2r *HTTP2Request) Display() []byte {
86-
_, err := h2r.bufReader.Discard(H2MagicLen)
89+
_, err := h2r.bufReader.Discard(ClientPrefaceLen)
8790
if err != nil {
8891
log.Println("[http2 request] Discard HTTP2 Magic error:", err)
8992
return h2r.reader.Bytes()

pkg/event_processor/http2_request_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestHttp2RequestParser(t *testing.T) {
4040
}
4141
t.Logf("TestHttp2RequestParser: wrot body:%d", i)
4242

43-
_, err = h2r.bufReader.Discard(H2MagicLen)
43+
_, err = h2r.bufReader.Discard(ClientPrefaceLen)
4444
if err != nil {
4545
t.Logf("[http2 request] Discard HTTP2 Magic error:%v", err)
4646
}

pkg/event_processor/http2_response.go

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"bufio"
1919
"bytes"
2020
"compress/gzip"
21+
"errors"
2122
"fmt"
2223
"io"
2324
"log"
@@ -26,6 +27,22 @@ import (
2627
"golang.org/x/net/http2/hpack"
2728
)
2829

30+
const frameHeaderLen = 9
31+
32+
// http2.FrameType
33+
// const (
34+
// FrameData FrameType = 0x0
35+
// FrameHeaders FrameType = 0x1
36+
// FramePriority FrameType = 0x2
37+
// FrameRSTStream FrameType = 0x3
38+
// FrameSettings FrameType = 0x4
39+
// FramePushPromise FrameType = 0x5
40+
// FramePing FrameType = 0x6
41+
// FrameGoAway FrameType = 0x7
42+
// FrameWindowUpdate FrameType = 0x8
43+
// FrameContinuation FrameType = 0x9
44+
// )
45+
2946
type HTTP2Response struct {
3047
framer *http2.Framer
3148
packerType PacketType
@@ -36,15 +53,37 @@ type HTTP2Response struct {
3653
}
3754

3855
func (h2r *HTTP2Response) detect(payload []byte) error {
39-
rd := bytes.NewReader(payload)
40-
buf := bufio.NewReader(rd)
41-
framer := http2.NewFramer(nil, buf)
42-
framer.ReadMetaHeaders = hpack.NewDecoder(0, nil)
43-
_, err := framer.ReadFrame()
44-
if err != nil {
45-
return err
56+
payloadLen := len(payload)
57+
if payloadLen < frameHeaderLen {
58+
return errors.New("Payload less than http2 frame Header")
59+
}
60+
// https://httpwg.org/specs/rfc7540.html#FrameHeader
61+
// All frames begin with a fixed 9-octet header followed by a variable-length payload.
62+
//
63+
// +-----------------------------------------------+
64+
// | Length (24) |
65+
// +---------------+---------------+---------------+
66+
// | Type (8) | Flags (8) |
67+
// +-+-------------+---------------+-------------------------------+
68+
// |R| Stream Identifier (31) |
69+
// +=+=============================================================+
70+
// | Frame Payload (0...) ...
71+
// +---------------------------------------------------------------+
72+
data := payload[0:frameHeaderLen]
73+
// currentFrameLen := uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
74+
currentFrameType := http2.FrameType(data[3])
75+
// Frame type in http2.FrameType
76+
if currentFrameType > http2.FrameContinuation {
77+
return errors.New("Invalid frame type")
78+
}
79+
// R: A reserved 1-bit field.
80+
// The semantics of this bit are undefined, and the bit MUST remain unset (0x0) when
81+
// sending and MUST be ignored when receiving.
82+
reservedBit := uint32(data[5]) >> 7
83+
if reservedBit == 0 {
84+
return nil
4685
}
47-
return nil
86+
return errors.New("Invalid reserved bit in frame header")
4887
}
4988

5089
func (h2r *HTTP2Response) Init() {

0 commit comments

Comments
 (0)