Skip to content

Commit db181cc

Browse files
committed
merge upstream http2: 2024-09-06(3c333c)
1 parent fb51d5b commit db181cc

File tree

5 files changed

+180
-77
lines changed

5 files changed

+180
-77
lines changed

internal/http2/frame.go

+37-3
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,9 @@ func (h2f *Framer) currentRequest(id uint32) *http.Request {
520520
// returned error is errFrameTooLarge. Other errors may be of type
521521
// ConnectionError, StreamError, or anything else from the underlying
522522
// reader.
523+
//
524+
// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID
525+
// indicates the stream responsible for the error.
523526
func (h2f *Framer) ReadFrame() (Frame, error) {
524527
h2f.errDetail = nil
525528
if h2f.lastFrame != nil {
@@ -1555,7 +1558,7 @@ func (fr *Framer) maxHeaderStringLen() int {
15551558
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
15561559
// merge them into the provided hf and returns a MetaHeadersFrame
15571560
// with the decoded hpack values.
1558-
func (h2f *Framer) readMetaFrame(hf *HeadersFrame, dumps []*dump.Dumper) (*MetaHeadersFrame, error) {
1561+
func (h2f *Framer) readMetaFrame(hf *HeadersFrame, dumps []*dump.Dumper) (Frame, error) {
15591562
if h2f.AllowIllegalReads {
15601563
return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
15611564
}
@@ -1598,6 +1601,7 @@ func (h2f *Framer) readMetaFrame(hf *HeadersFrame, dumps []*dump.Dumper) (*MetaH
15981601
if size > remainSize {
15991602
hdec.SetEmitEnabled(false)
16001603
mh.Truncated = true
1604+
remainSize = 0
16011605
return
16021606
}
16031607
remainSize -= size
@@ -1621,8 +1625,38 @@ func (h2f *Framer) readMetaFrame(hf *HeadersFrame, dumps []*dump.Dumper) (*MetaH
16211625
var hc headersOrContinuation = hf
16221626
for {
16231627
frag := hc.HeaderBlockFragment()
1628+
1629+
// Avoid parsing large amounts of headers that we will then discard.
1630+
// If the sender exceeds the max header list size by too much,
1631+
// skip parsing the fragment and close the connection.
1632+
//
1633+
// "Too much" is either any CONTINUATION frame after we've already
1634+
// exceeded the max header list size (in which case remainSize is 0),
1635+
// or a frame whose encoded size is more than twice the remaining
1636+
// header list bytes we're willing to accept.
1637+
if int64(len(frag)) > int64(2*remainSize) {
1638+
if VerboseLogs {
1639+
log.Printf("http2: header list too large")
1640+
}
1641+
// It would be nice to send a RST_STREAM before sending the GOAWAY,
1642+
// but the structure of the server's frame writer makes this difficult.
1643+
return mh, ConnectionError(ErrCodeProtocol)
1644+
}
1645+
1646+
// Also close the connection after any CONTINUATION frame following an
1647+
// invalid header, since we stop tracking the size of the headers after
1648+
// an invalid one.
1649+
if invalid != nil {
1650+
if VerboseLogs {
1651+
log.Printf("http2: invalid header: %v", invalid)
1652+
}
1653+
// It would be nice to send a RST_STREAM before sending the GOAWAY,
1654+
// but the structure of the server's frame writer makes this difficult.
1655+
return mh, ConnectionError(ErrCodeProtocol)
1656+
}
1657+
16241658
if _, err := hdec.Write(frag); err != nil {
1625-
return nil, ConnectionError(ErrCodeCompression)
1659+
return mh, ConnectionError(ErrCodeCompression)
16261660
}
16271661

16281662
if hc.HeadersEnded() {
@@ -1639,7 +1673,7 @@ func (h2f *Framer) readMetaFrame(hf *HeadersFrame, dumps []*dump.Dumper) (*MetaH
16391673
mh.HeadersFrame.invalidate()
16401674

16411675
if err := hdec.Close(); err != nil {
1642-
return nil, ConnectionError(ErrCodeCompression)
1676+
return mh, ConnectionError(ErrCodeCompression)
16431677
}
16441678
if invalid != nil {
16451679
h2f.errDetail = invalid

internal/http2/http2.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ package http2
77
import (
88
"bufio"
99
"crypto/tls"
10-
"golang.org/x/net/http/httpguts"
1110
"net/http"
1211
"os"
1312
"sort"
1413
"strconv"
1514
"strings"
1615
"sync"
16+
17+
"golang.org/x/net/http/httpguts"
1718
)
1819

1920
var (
@@ -50,9 +51,7 @@ const (
5051
initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
5152
)
5253

53-
var (
54-
clientPreface = []byte(ClientPreface)
55-
)
54+
var clientPreface = []byte(ClientPreface)
5655

5756
// validWireHeaderFieldName reports whether v is a valid header field
5857
// name (key). See httpguts.ValidHeaderName for the base rules.

internal/http2/pipe.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ func (p *pipe) Read(d []byte) (n int, err error) {
7777
}
7878
}
7979

80-
var errClosedPipeWrite = errors.New("write on closed buffer")
80+
var (
81+
errClosedPipeWrite = errors.New("write on closed buffer")
82+
errUninitializedPipeWrite = errors.New("write on uninitialized buffer")
83+
)
8184

8285
// Write copies bytes from p into the buffer and wakes a reader.
8386
// It is an error to write more data than the buffer can hold.
@@ -91,6 +94,12 @@ func (p *pipe) Write(d []byte) (n int, err error) {
9194
if p.err != nil || p.breakErr != nil {
9295
return 0, errClosedPipeWrite
9396
}
97+
// pipe.setBuffer is never invoked, leaving the buffer uninitialized.
98+
// We shouldn't try to write to an uninitialized pipe,
99+
// but returning an error is better than panicking.
100+
if p.b == nil {
101+
return 0, errUninitializedPipeWrite
102+
}
94103
return p.b.Write(d)
95104
}
96105

internal/http2/timer.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
package http2
5+
6+
import "time"
7+
8+
// A timer is a time.Timer, as an interface which can be replaced in tests.
9+
type timer = interface {
10+
C() <-chan time.Time
11+
Reset(d time.Duration) bool
12+
Stop() bool
13+
}
14+
15+
// timeTimer adapts a time.Timer to the timer interface.
16+
type timeTimer struct {
17+
*time.Timer
18+
}
19+
20+
func (t timeTimer) C() <-chan time.Time { return t.Timer.C }

0 commit comments

Comments
 (0)