Skip to content

Commit 247aa96

Browse files
committed
port quic-go v0.57.1
Signed-off-by: roc <roc@imroc.cc>
1 parent e3ea2a2 commit 247aa96

File tree

7 files changed

+168
-90
lines changed

7 files changed

+168
-90
lines changed

internal/http3/client.go

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ type ClientConn struct {
6262

6363
// maxResponseHeaderBytes specifies a limit on how many response bytes are
6464
// allowed in the server's response header.
65-
maxResponseHeaderBytes uint64
65+
maxResponseHeaderBytes int
6666

6767
// disableCompression, if true, prevents the Transport from requesting compression with an
6868
// "Accept-Encoding: gzip" request header when the Request contains no existing Accept-Encoding value.
@@ -86,7 +86,7 @@ func newClientConn(
8686
additionalSettings map[uint64]uint64,
8787
streamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error),
8888
uniStreamHijacker func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool),
89-
maxResponseHeaderBytes int64,
89+
maxResponseHeaderBytes int,
9090
disableCompression bool,
9191
logger *slog.Logger,
9292
) *ClientConn {
@@ -100,9 +100,9 @@ func newClientConn(
100100
if maxResponseHeaderBytes <= 0 {
101101
c.maxResponseHeaderBytes = defaultMaxResponseHeaderBytes
102102
} else {
103-
c.maxResponseHeaderBytes = uint64(maxResponseHeaderBytes)
103+
c.maxResponseHeaderBytes = maxResponseHeaderBytes
104104
}
105-
c.decoder = qpack.NewDecoder(func(hf qpack.HeaderField) {})
105+
c.decoder = qpack.NewDecoder()
106106
c.requestWriter = newRequestWriter()
107107
c.conn = newConnection(
108108
conn.Context(),
@@ -143,10 +143,15 @@ func (c *ClientConn) setupConn() error {
143143
b := make([]byte, 0, 64)
144144
b = quicvarint.Append(b, streamTypeControlStream)
145145
// send the SETTINGS frame
146-
b = (&settingsFrame{Datagram: c.enableDatagrams, Other: c.additionalSettings}).Append(b)
146+
b = (&settingsFrame{
147+
Datagram: c.enableDatagrams,
148+
Other: c.additionalSettings,
149+
MaxFieldSectionSize: int64(c.maxResponseHeaderBytes),
150+
}).Append(b)
147151
if c.conn.qlogger != nil {
148152
sf := qlog.SettingsFrame{
149-
Other: maps.Clone(c.additionalSettings),
153+
MaxFieldSectionSize: int64(c.maxResponseHeaderBytes),
154+
Other: maps.Clone(c.additionalSettings),
150155
}
151156
if c.enableDatagrams {
152157
sf.Datagram = pointer(true)
@@ -356,32 +361,38 @@ func (c *ClientConn) sendRequestBody(str *RequestStream, body io.ReadCloser, con
356361

357362
func (c *ClientConn) doRequest(req *http.Request, str *RequestStream) (*http.Response, error) {
358363
trace := httptrace.ContextClientTrace(req.Context())
364+
var sendingReqFailed bool
359365
if err := str.sendRequestHeader(req); err != nil {
360366
traceWroteRequest(trace, err)
361-
return nil, err
367+
if c.logger != nil {
368+
c.logger.Debug("error writing request", "error", err)
369+
}
370+
sendingReqFailed = true
362371
}
363-
if req.Body == nil {
364-
traceWroteRequest(trace, nil)
365-
str.Close()
366-
} else {
367-
// send the request body asynchronously
368-
go func() {
369-
contentLength := int64(-1)
370-
// According to the documentation for http.Request.ContentLength,
371-
// a value of 0 with a non-nil Body is also treated as unknown content length.
372-
if req.ContentLength > 0 {
373-
contentLength = req.ContentLength
374-
}
375-
dumps := dump.GetDumpers(req.Context(), c.Dump)
376-
err := c.sendRequestBody(str, req.Body, contentLength, dumps)
377-
traceWroteRequest(trace, err)
378-
if err != nil {
379-
if c.Debugf != nil {
380-
c.Debugf("error writing request: %s", err.Error())
381-
}
382-
}
372+
if !sendingReqFailed {
373+
if req.Body == nil {
374+
traceWroteRequest(trace, nil)
383375
str.Close()
384-
}()
376+
} else {
377+
// send the request body asynchronously
378+
go func() {
379+
contentLength := int64(-1)
380+
// According to the documentation for http.Request.ContentLength,
381+
// a value of 0 with a non-nil Body is also treated as unknown content length.
382+
if req.ContentLength > 0 {
383+
contentLength = req.ContentLength
384+
}
385+
dumps := dump.GetDumpers(req.Context(), c.Dump)
386+
err := c.sendRequestBody(str, req.Body, contentLength, dumps)
387+
traceWroteRequest(trace, err)
388+
if err != nil {
389+
if c.logger != nil {
390+
c.logger.Debug("error writing request", "error", err)
391+
}
392+
}
393+
str.Close()
394+
}()
395+
}
385396
}
386397

387398
// copy from net/http: support 1xx responses

internal/http3/conn.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func newConnection(
8080
logger: logger,
8181
idleTimeout: idleTimeout,
8282
enableDatagrams: enableDatagrams,
83-
decoder: qpack.NewDecoder(func(hf qpack.HeaderField) {}),
83+
decoder: qpack.NewDecoder(),
8484
receivedSettings: make(chan struct{}),
8585
streams: make(map[quic.StreamID]*stateTrackingStream),
8686
maxStreamID: InvalidStreamID,
@@ -151,7 +151,7 @@ func (c *Conn) openRequestStream(
151151
requestWriter *requestWriter,
152152
reqDone chan<- struct{},
153153
disableCompression bool,
154-
maxHeaderBytes uint64,
154+
maxHeaderBytes int,
155155
) (*RequestStream, error) {
156156
c.streamMx.Lock()
157157
maxStreamID := c.maxStreamID
@@ -199,25 +199,30 @@ func (c *Conn) openRequestStream(
199199
), nil
200200
}
201201

202-
func (c *Conn) decodeTrailers(r io.Reader, streamID quic.StreamID, hf *headersFrame, maxHeaderBytes uint64) (http.Header, error) {
203-
if hf.Length > maxHeaderBytes {
202+
func (c *Conn) decodeTrailers(r io.Reader, streamID quic.StreamID, hf *headersFrame, maxHeaderBytes int) (http.Header, error) {
203+
if hf.Length > uint64(maxHeaderBytes) {
204204
maybeQlogInvalidHeadersFrame(c.qlogger, streamID, hf.Length)
205-
return nil, fmt.Errorf("HEADERS frame too large: %d bytes (max: %d)", hf.Length, maxHeaderBytes)
205+
return nil, fmt.Errorf("http3: HEADERS frame too large: %d bytes (max: %d)", hf.Length, maxHeaderBytes)
206206
}
207207

208208
b := make([]byte, hf.Length)
209209
if _, err := io.ReadFull(r, b); err != nil {
210210
return nil, err
211211
}
212-
fields, err := c.decoder.DecodeFull(b)
212+
decodeFn := c.decoder.Decode(b)
213+
var fields []qpack.HeaderField
214+
if c.qlogger != nil {
215+
fields = make([]qpack.HeaderField, 0, 16)
216+
}
217+
trailers, err := parseTrailers(decodeFn, &fields)
213218
if err != nil {
214219
maybeQlogInvalidHeadersFrame(c.qlogger, streamID, hf.Length)
215220
return nil, err
216221
}
217222
if c.qlogger != nil {
218223
qlogParsedHeadersFrame(c.qlogger, streamID, hf, fields)
219224
}
220-
return parseTrailers(fields)
225+
return trailers, nil
221226
}
222227

223228
func (c *Conn) CloseWithError(code quic.ApplicationErrorCode, msg string) error {

internal/http3/error_codes.go

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,25 @@ import (
99
type ErrCode quic.ApplicationErrorCode
1010

1111
const (
12-
ErrCodeNoError ErrCode = 0x100
13-
ErrCodeGeneralProtocolError ErrCode = 0x101
14-
ErrCodeInternalError ErrCode = 0x102
15-
ErrCodeStreamCreationError ErrCode = 0x103
16-
ErrCodeClosedCriticalStream ErrCode = 0x104
17-
ErrCodeFrameUnexpected ErrCode = 0x105
18-
ErrCodeFrameError ErrCode = 0x106
19-
ErrCodeExcessiveLoad ErrCode = 0x107
20-
ErrCodeIDError ErrCode = 0x108
21-
ErrCodeSettingsError ErrCode = 0x109
22-
ErrCodeMissingSettings ErrCode = 0x10a
23-
ErrCodeRequestRejected ErrCode = 0x10b
24-
ErrCodeRequestCanceled ErrCode = 0x10c
25-
ErrCodeRequestIncomplete ErrCode = 0x10d
26-
ErrCodeMessageError ErrCode = 0x10e
27-
ErrCodeConnectError ErrCode = 0x10f
28-
ErrCodeVersionFallback ErrCode = 0x110
29-
ErrCodeDatagramError ErrCode = 0x33
12+
ErrCodeNoError ErrCode = 0x100
13+
ErrCodeGeneralProtocolError ErrCode = 0x101
14+
ErrCodeInternalError ErrCode = 0x102
15+
ErrCodeStreamCreationError ErrCode = 0x103
16+
ErrCodeClosedCriticalStream ErrCode = 0x104
17+
ErrCodeFrameUnexpected ErrCode = 0x105
18+
ErrCodeFrameError ErrCode = 0x106
19+
ErrCodeExcessiveLoad ErrCode = 0x107
20+
ErrCodeIDError ErrCode = 0x108
21+
ErrCodeSettingsError ErrCode = 0x109
22+
ErrCodeMissingSettings ErrCode = 0x10a
23+
ErrCodeRequestRejected ErrCode = 0x10b
24+
ErrCodeRequestCanceled ErrCode = 0x10c
25+
ErrCodeRequestIncomplete ErrCode = 0x10d
26+
ErrCodeMessageError ErrCode = 0x10e
27+
ErrCodeConnectError ErrCode = 0x10f
28+
ErrCodeVersionFallback ErrCode = 0x110
29+
ErrCodeDatagramError ErrCode = 0x33
30+
ErrCodeQPACKDecompressionFailed ErrCode = 0x200
3031
)
3132

3233
func (e ErrCode) String() string {
@@ -75,6 +76,8 @@ func (e ErrCode) string() string {
7576
return "H3_VERSION_FALLBACK"
7677
case ErrCodeDatagramError:
7778
return "H3_DATAGRAM_ERROR"
79+
case ErrCodeQPACKDecompressionFailed:
80+
return "QPACK_DECOMPRESSION_FAILED"
7881
default:
7982
return ""
8083
}

internal/http3/frames.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,17 +179,20 @@ func (f *headersFrame) Append(b []byte) []byte {
179179
}
180180

181181
const (
182+
// SETTINGS_MAX_FIELD_SECTION_SIZE
183+
settingMaxFieldSectionSize = 0x6
182184
// Extended CONNECT, RFC 9220
183185
settingExtendedConnect = 0x8
184186
// HTTP Datagrams, RFC 9297
185187
settingDatagram = 0x33
186188
)
187189

188190
type settingsFrame struct {
189-
Datagram bool // HTTP Datagrams, RFC 9297
190-
ExtendedConnect bool // Extended CONNECT, RFC 9220
191+
MaxFieldSectionSize int64 // SETTINGS_MAX_FIELD_SECTION_SIZE, -1 if not set
191192

192-
Other map[uint64]uint64 // all settings that we don't explicitly recognize
193+
Datagram bool // HTTP Datagrams, RFC 9297
194+
ExtendedConnect bool // Extended CONNECT, RFC 9220
195+
Other map[uint64]uint64 // all settings that we don't explicitly recognize
193196
}
194197

195198
func pointer[T any](v T) *T {
@@ -207,10 +210,10 @@ func parseSettingsFrame(r *countingByteReader, l uint64, streamID quic.StreamID,
207210
}
208211
return nil, err
209212
}
210-
frame := &settingsFrame{}
213+
frame := &settingsFrame{MaxFieldSectionSize: -1}
211214
b := bytes.NewReader(buf)
212-
var settingsFrame qlog.SettingsFrame
213-
var readDatagram, readExtendedConnect bool
215+
settingsFrame := qlog.SettingsFrame{MaxFieldSectionSize: -1}
216+
var readMaxFieldSectionSize, readDatagram, readExtendedConnect bool
214217
for b.Len() > 0 {
215218
id, err := quicvarint.Read(b)
216219
if err != nil { // should not happen. We allocated the whole frame already.
@@ -222,6 +225,13 @@ func parseSettingsFrame(r *countingByteReader, l uint64, streamID quic.StreamID,
222225
}
223226

224227
switch id {
228+
case settingMaxFieldSectionSize:
229+
if readMaxFieldSectionSize {
230+
return nil, fmt.Errorf("duplicate setting: %d", id)
231+
}
232+
readMaxFieldSectionSize = true
233+
frame.MaxFieldSectionSize = int64(val)
234+
settingsFrame.MaxFieldSectionSize = int64(val)
225235
case settingExtendedConnect:
226236
if readExtendedConnect {
227237
return nil, fmt.Errorf("duplicate setting: %d", id)
@@ -274,6 +284,9 @@ func parseSettingsFrame(r *countingByteReader, l uint64, streamID quic.StreamID,
274284
func (f *settingsFrame) Append(b []byte) []byte {
275285
b = quicvarint.Append(b, 0x4)
276286
var l int
287+
if f.MaxFieldSectionSize >= 0 {
288+
l += quicvarint.Len(settingMaxFieldSectionSize) + quicvarint.Len(uint64(f.MaxFieldSectionSize))
289+
}
277290
for id, val := range f.Other {
278291
l += quicvarint.Len(id) + quicvarint.Len(val)
279292
}
@@ -284,6 +297,10 @@ func (f *settingsFrame) Append(b []byte) []byte {
284297
l += quicvarint.Len(settingExtendedConnect) + quicvarint.Len(1)
285298
}
286299
b = quicvarint.Append(b, uint64(l))
300+
if f.MaxFieldSectionSize >= 0 {
301+
b = quicvarint.Append(b, settingMaxFieldSectionSize)
302+
b = quicvarint.Append(b, uint64(f.MaxFieldSectionSize))
303+
}
287304
if f.Datagram {
288305
b = quicvarint.Append(b, settingDatagram)
289306
b = quicvarint.Append(b, 1)

0 commit comments

Comments
 (0)