Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update read header frame #1156

Merged
merged 2 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions bfe_http2/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,7 @@ func (fr *Framer) readMetaFrame(f *HeadersFrame) (*MetaHeadersFrame, error) {
hdec.SetEmitEnabled(false)
mh.Truncated = true
state.H2ErrMaxHeaderListSize.Inc(1)
remainSize = 0
return maxHeaderListSizeError{
streamID: f.FrameHeader.StreamID,
curHeaderListSize: fr.maxHeaderListSize() - remainSize + size,
Expand All @@ -1525,6 +1526,35 @@ func (fr *Framer) readMetaFrame(f *HeadersFrame) (*MetaHeadersFrame, error) {
var err error
for {
frag := hc.HeaderBlockFragment()

// Avoid parsing large amounts of headers that we will then discard.
// If the sender exceeds the max header list size by too much,
// skip parsing the fragment and close the connection.
//
// "Too much" is either any CONTINUATION frame after we've already
// exceeded the max header list size (in which case remainSize is 0),
// or a frame whose encoded size is more than twice the remaining
// header list bytes we're willing to accept.
if int64(len(frag)) > int64(2*remainSize) {
if VerboseLogs {
log.Printf("http2: header list too large")
}
// It would be nice to send a RST_STREAM before sending the GOAWAY,
// but the structure of the server's frame writer makes this difficult.
return nil, ConnectionError{ErrCodeProtocol, "http2: header list too large"}
}

// Also close the connection after any CONTINUATION frame following an
// invalid header, since we stop tracking the size of the headers after
// an invalid one.
if invalid != nil {
if VerboseLogs {
log.Printf("http2: invalid header: %v", invalid)
}
// It would be nice to send a RST_STREAM before sending the GOAWAY,
// but the structure of the server's frame writer makes this difficult.
return nil, ConnectionError{ErrCodeProtocol, fmt.Sprintf("http2: invalid header: %v", invalid)}
}
blockSize += len(frag)
if _, err = hdec.Write(frag); err != nil {
// do not return ConnectionError err type,
Expand Down
4 changes: 2 additions & 2 deletions bfe_http2/frame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ func TestMetaFrameHeader(t *testing.T) {
maxHeaderListSize: (1 << 10) / 2,
want: maxHeaderListSizeError{
streamID: 1,
curHeaderListSize: 536,
curHeaderListSize: 550,
maxHeaderListSize: 512,
},
},
Expand Down Expand Up @@ -1033,7 +1033,7 @@ func TestMetaFrameHeader(t *testing.T) {
}
return fmt.Sprintf("value %#v", v)
}
t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want))
t.Errorf(" %s:\n got: %v\nwant: %s", name, str(got), str(tt.want))
}
if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) {
t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason)
Expand Down
Loading