diff options
| author | qiulaidongfeng <2645477756@qq.com> | 2026-03-13 23:43:05 +0800 |
|---|---|---|
| committer | Nicholas Husin <nsh@golang.org> | 2026-03-23 12:27:43 -0700 |
| commit | e1bc5cea825171f68f928686ed02a0d0abddd84c (patch) | |
| tree | d3c98995c7dd19f19a2cb982170d28a9262007cd /src/net/http | |
| parent | 224489f11c2e0b394e93980fc8292c52f60b18a8 (diff) | |
| download | go-e1bc5cea825171f68f928686ed02a0d0abddd84c.tar.xz | |
net/http/internal/http2: modernize the package
This CL is mostly generated by running go fix. Manual edits have also been
selectively done to modernize the package where doing so is straightforward; for
example, using slices.Contains in lieu of strSliceContains.
Change-Id: Ie2942481672c56c370e2df0f172cf3e480a12bc5
Reviewed-on: https://go-review.googlesource.com/c/go/+/757220
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Nicholas Husin <nsh@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/net/http')
19 files changed, 119 insertions, 169 deletions
diff --git a/src/net/http/internal/http2/client_conn_pool.go b/src/net/http/internal/http2/client_conn_pool.go index ded7c39e77..042071c559 100644 --- a/src/net/http/internal/http2/client_conn_pool.go +++ b/src/net/http/internal/http2/client_conn_pool.go @@ -10,6 +10,7 @@ import ( "context" "errors" "net" + "slices" "sync" ) @@ -211,10 +212,8 @@ func (c *addConnCall) run(t *Transport, key string, nc net.Conn) { // p.mu must be held func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) { - for _, v := range p.conns[key] { - if v == cc { - return - } + if slices.Contains(p.conns[key], cc) { + return } if p.conns == nil { p.conns = make(map[string][]*ClientConn) diff --git a/src/net/http/internal/http2/databuffer.go b/src/net/http/internal/http2/databuffer.go index e6f55cbd16..fe700d30c8 100644 --- a/src/net/http/internal/http2/databuffer.go +++ b/src/net/http/internal/http2/databuffer.go @@ -21,11 +21,11 @@ import ( // improved enough that we can instead allocate chunks like this: // make([]byte, max(16<<10, expectedBytesRemaining)) var dataChunkPools = [...]sync.Pool{ - {New: func() interface{} { return new([1 << 10]byte) }}, - {New: func() interface{} { return new([2 << 10]byte) }}, - {New: func() interface{} { return new([4 << 10]byte) }}, - {New: func() interface{} { return new([8 << 10]byte) }}, - {New: func() interface{} { return new([16 << 10]byte) }}, + {New: func() any { return new([1 << 10]byte) }}, + {New: func() any { return new([2 << 10]byte) }}, + {New: func() any { return new([4 << 10]byte) }}, + {New: func() any { return new([8 << 10]byte) }}, + {New: func() any { return new([16 << 10]byte) }}, } func getDataBufferChunk(size int64) []byte { @@ -121,10 +121,7 @@ func (b *dataBuffer) Write(p []byte) (int, error) { // If the last chunk is empty, allocate a new chunk. Try to allocate // enough to fully copy p plus any additional bytes we expect to // receive. However, this may allocate less than len(p). - want := int64(len(p)) - if b.expected > want { - want = b.expected - } + want := max(b.expected, int64(len(p))) chunk := b.lastChunkOrAlloc(want) n := copy(chunk[b.w:], p) p = p[n:] diff --git a/src/net/http/internal/http2/databuffer_test.go b/src/net/http/internal/http2/databuffer_test.go index 32cd5f38b3..57f292fda2 100644 --- a/src/net/http/internal/http2/databuffer_test.go +++ b/src/net/http/internal/http2/databuffer_test.go @@ -8,36 +8,37 @@ import ( "bytes" "fmt" "reflect" + "strings" "testing" ) func fmtDataChunk(chunk []byte) string { - out := "" + var out strings.Builder var last byte var count int for _, c := range chunk { if c != last { if count > 0 { - out += fmt.Sprintf(" x %d ", count) + out.WriteString(fmt.Sprintf(" x %d ", count)) count = 0 } - out += string([]byte{c}) + out.WriteString(string([]byte{c})) last = c } count++ } if count > 0 { - out += fmt.Sprintf(" x %d", count) + out.WriteString(fmt.Sprintf(" x %d", count)) } - return out + return out.String() } func fmtDataChunks(chunks [][]byte) string { - var out string + var out strings.Builder for _, chunk := range chunks { - out += fmt.Sprintf("{%q}", fmtDataChunk(chunk)) + out.WriteString(fmt.Sprintf("{%q}", fmtDataChunk(chunk))) } - return out + return out.String() } func testDataBuffer(t *testing.T, wantBytes []byte, setup func(t *testing.T) *dataBuffer) { diff --git a/src/net/http/internal/http2/errors.go b/src/net/http/internal/http2/errors.go index 35c34b7ba5..58822972bc 100644 --- a/src/net/http/internal/http2/errors.go +++ b/src/net/http/internal/http2/errors.go @@ -104,14 +104,14 @@ func (e StreamError) As(target any) bool { if dstType.NumField() != numField { return false } - for i := 0; i < numField; i++ { + for i := range numField { sf := srcType.Field(i) df := dstType.Field(i) if sf.Name != df.Name || !sf.Type.ConvertibleTo(df.Type) { return false } } - for i := 0; i < numField; i++ { + for i := range numField { df := dst.Field(i) df.Set(src.Field(i).Convert(df.Type())) } diff --git a/src/net/http/internal/http2/export_test.go b/src/net/http/internal/http2/export_test.go index 8593ea3628..c5207851b8 100644 --- a/src/net/http/internal/http2/export_test.go +++ b/src/net/http/internal/http2/export_test.go @@ -170,7 +170,7 @@ func init() { testHookOnPanicMu = new(sync.Mutex) } -func SetTestHookOnPanic(t testing.TB, f func(sc *serverConn, panicVal interface{}) (rePanic bool)) { +func SetTestHookOnPanic(t testing.TB, f func(sc *serverConn, panicVal any) (rePanic bool)) { testHookOnPanicMu.Lock() defer testHookOnPanicMu.Unlock() old := testHookOnPanic diff --git a/src/net/http/internal/http2/frame.go b/src/net/http/internal/http2/frame.go index 149d99b547..a2de8c2719 100644 --- a/src/net/http/internal/http2/frame.go +++ b/src/net/http/internal/http2/frame.go @@ -196,7 +196,7 @@ func (h FrameHeader) writeDebug(buf *bytes.Buffer) { if h.Flags != 0 { buf.WriteString(" flags=") set := 0 - for i := uint8(0); i < 8; i++ { + for i := range uint8(8) { if h.Flags&(1<<i) == 0 { continue } @@ -229,7 +229,7 @@ func (h *FrameHeader) invalidate() { h.valid = false } // frame header bytes. // Used only by ReadFrameHeader. var fhBytes = sync.Pool{ - New: func() interface{} { + New: func() any { buf := make([]byte, frameHeaderLen) return &buf }, @@ -343,8 +343,8 @@ type Framer struct { debugFramer *Framer // only use for logging written writes debugFramerBuf *bytes.Buffer - debugReadLoggerf func(string, ...interface{}) - debugWriteLoggerf func(string, ...interface{}) + debugReadLoggerf func(string, ...any) + debugWriteLoggerf func(string, ...any) frameCache *frameCache // nil if frames aren't reused (default) } @@ -838,7 +838,7 @@ func (f *SettingsFrame) HasDuplicates() bool { // If it's small enough (the common case), just do the n^2 // thing and avoid a map allocation. if num < 10 { - for i := 0; i < num; i++ { + for i := range num { idi := f.Setting(i).ID for j := i + 1; j < num; j++ { idj := f.Setting(j).ID @@ -850,7 +850,7 @@ func (f *SettingsFrame) HasDuplicates() bool { return false } seen := map[SettingID]bool{} - for i := 0; i < num; i++ { + for i := range num { id := f.Setting(i).ID if seen[id] { return true diff --git a/src/net/http/internal/http2/frame_test.go b/src/net/http/internal/http2/frame_test.go index 488b2eb346..43cd66bfc3 100644 --- a/src/net/http/internal/http2/frame_test.go +++ b/src/net/http/internal/http2/frame_test.go @@ -1132,7 +1132,7 @@ func TestMetaFrameHeader(t *testing.T) { tests := [...]struct { name string w func(*Framer) - want interface{} // *MetaHeaderFrame or error + want any // *MetaHeaderFrame or error wantErrReason string maxHeaderListSize uint32 }{ @@ -1181,7 +1181,7 @@ func TestMetaFrameHeader(t *testing.T) { name: "max_header_list_truncated", w: func(f *Framer) { var pairs = []string{":method", "GET", ":path", "/"} - for i := 0; i < 100; i++ { + for range 100 { pairs = append(pairs, "foo", "bar") } all := encodeHeaderRaw(t, pairs...) @@ -1279,7 +1279,7 @@ func TestMetaFrameHeader(t *testing.T) { name = fmt.Sprintf("test index %d", i) } - var got interface{} + var got any var err error got, err = f.ReadFrame() if err != nil { @@ -1302,7 +1302,7 @@ func TestMetaFrameHeader(t *testing.T) { } } } - str := func(v interface{}) string { + str := func(v any) string { if _, ok := v.(error); ok { return fmt.Sprintf("error %v", v) } else { @@ -1325,21 +1325,21 @@ func TestSetReuseFrames(t *testing.T) { // SetReuseFrames only currently implements reuse of DataFrames. firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t) - for i := 0; i < 10; i++ { + for range 10 { df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) if df != firstDf { t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) } } - for i := 0; i < 10; i++ { + for range 10 { df := readAndVerifyDataFrame("", 0, fr, buf, t) if df != firstDf { t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) } } - for i := 0; i < 10; i++ { + for range 10 { df := readAndVerifyDataFrame("HHH", 3, fr, buf, t) if df != firstDf { t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) @@ -1354,7 +1354,7 @@ func TestSetReuseFramesMoreThanOnce(t *testing.T) { firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t) fr.SetReuseFrames() - for i := 0; i < 10; i++ { + for range 10 { df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) // SetReuseFrames should be idempotent fr.SetReuseFrames() @@ -1367,11 +1367,11 @@ func TestSetReuseFramesMoreThanOnce(t *testing.T) { func TestNoSetReuseFrames(t *testing.T) { fr, buf := testFramer() const numNewDataFrames = 10 - dfSoFar := make([]interface{}, numNewDataFrames) + dfSoFar := make([]any, numNewDataFrames) // Check that DataFrames are not reused if SetReuseFrames wasn't called. // SetReuseFrames only currently implements reuse of DataFrames. - for i := 0; i < numNewDataFrames; i++ { + for i := range numNewDataFrames { df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) for _, item := range dfSoFar { if df == item { diff --git a/src/net/http/internal/http2/gotrack.go b/src/net/http/internal/http2/gotrack.go index 9921ca096d..ba0db1690c 100644 --- a/src/net/http/internal/http2/gotrack.go +++ b/src/net/http/internal/http2/gotrack.go @@ -79,7 +79,7 @@ func curGoroutineID() uint64 { } var littleBuf = sync.Pool{ - New: func() interface{} { + New: func() any { buf := make([]byte, 64) return &buf }, diff --git a/src/net/http/internal/http2/gotrack_test.go b/src/net/http/internal/http2/gotrack_test.go index 18b8961c05..35d12a7d73 100644 --- a/src/net/http/internal/http2/gotrack_test.go +++ b/src/net/http/internal/http2/gotrack_test.go @@ -14,7 +14,7 @@ func TestGoroutineLock(t *testing.T) { g := newGoroutineLock() g.check() - sawPanic := make(chan interface{}) + sawPanic := make(chan any) go func() { defer func() { sawPanic <- recover() }() g.check() // should panic diff --git a/src/net/http/internal/http2/http2.go b/src/net/http/internal/http2/http2.go index 425e90c4f2..86c28e888b 100644 --- a/src/net/http/internal/http2/http2.go +++ b/src/net/http/internal/http2/http2.go @@ -20,7 +20,7 @@ import ( "fmt" "net" "os" - "sort" + "slices" "strconv" "strings" "sync" @@ -273,7 +273,7 @@ func newBufferedWriter(conn net.Conn, timeout time.Duration) *bufferedWriter { const bufWriterPoolBufferSize = 4 << 10 var bufWriterPool = sync.Pool{ - New: func() interface{} { + New: func() any { return bufio.NewWriterSize(nil, bufWriterPoolBufferSize) }, } @@ -376,16 +376,12 @@ type connectionStater interface { ConnectionState() tls.ConnectionState } -var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }} +var sorterPool = sync.Pool{New: func() any { return new(sorter) }} type sorter struct { v []string // owned by sorter } -func (s *sorter) Len() int { return len(s.v) } -func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] } -func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] } - // Keys returns the sorted keys of h. // // The returned slice is only valid until s used again or returned to @@ -396,19 +392,10 @@ func (s *sorter) Keys(h Header) []string { keys = append(keys, k) } s.v = keys - sort.Sort(s) + slices.Sort(s.v) return keys } -func (s *sorter) SortStrings(ss []string) { - // Our sorter works on s.v, which sorter owns, so - // stash it away while we sort the user's buffer. - save := s.v - s.v = ss - sort.Sort(s) - s.v = save -} - // incomparable is a zero-width, non-comparable type. Adding it to a struct // makes that struct also non-comparable, and generally doesn't add // any size (as long as it's first). diff --git a/src/net/http/internal/http2/http2_test.go b/src/net/http/internal/http2/http2_test.go index af82416046..ad1b9a6d06 100644 --- a/src/net/http/internal/http2/http2_test.go +++ b/src/net/http/internal/http2/http2_test.go @@ -45,7 +45,6 @@ func TestSettingString(t *testing.T) { } func TestSorterPoolAllocs(t *testing.T) { - ss := []string{"a", "b", "c"} h := Header{ "a": nil, "b": nil, @@ -53,12 +52,6 @@ func TestSorterPoolAllocs(t *testing.T) { } sorter := new(sorter) - if allocs := testing.AllocsPerRun(100, func() { - sorter.SortStrings(ss) - }); allocs >= 1 { - t.Logf("SortStrings allocs = %v; want <1", allocs) - } - if allocs := testing.AllocsPerRun(5, func() { if len(sorter.Keys(h)) != 3 { t.Fatal("wrong result") diff --git a/src/net/http/internal/http2/server.go b/src/net/http/internal/http2/server.go index ebfe16f59a..81f385d702 100644 --- a/src/net/http/internal/http2/server.go +++ b/src/net/http/internal/http2/server.go @@ -44,6 +44,7 @@ import ( "os" "reflect" "runtime" + "slices" "strconv" "strings" "sync" @@ -73,7 +74,7 @@ var ( ) var responseWriterStatePool = sync.Pool{ - New: func() interface{} { + New: func() any { rws := &responseWriterState{} rws.bw = bufio.NewWriterSize(chunkWriter{rws}, handlerChunkWriteSize) return rws @@ -84,7 +85,7 @@ var responseWriterStatePool = sync.Pool{ var ( testHookOnConn func() testHookOnPanicMu *sync.Mutex // nil except in tests - testHookOnPanic func(sc *serverConn, panicVal interface{}) (rePanic bool) + testHookOnPanic func(sc *serverConn, panicVal any) (rePanic bool) ) // Server is an HTTP/2 server. @@ -357,7 +358,7 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon streams: make(map[uint32]*stream), readFrameCh: make(chan readFrameResult), wantWriteFrameCh: make(chan FrameWriteRequest, 8), - serveMsgCh: make(chan interface{}, 8), + serveMsgCh: make(chan any, 8), wroteFrameCh: make(chan frameWriteResult, 1), // buffered; one send in writeFrameAsync bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way doneServing: make(chan struct{}), @@ -510,7 +511,7 @@ type serverConn struct { wantWriteFrameCh chan FrameWriteRequest // from handlers -> serve wroteFrameCh chan frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes bodyReadCh chan bodyReadMsg // from handlers -> serve - serveMsgCh chan interface{} // misc messages & code to send to / run on the serve loop + serveMsgCh chan any // misc messages & code to send to / run on the serve loop flow outflow // conn-wide (not stream-specific) outbound flow control inflow inflow // conn-wide inbound flow control tlsState *tls.ConnectionState // shared by all handlers, like net/http @@ -667,13 +668,13 @@ func (sc *serverConn) setConnState(state ConnState) { sc.hs.ConnState(sc.conn, state) } -func (sc *serverConn) vlogf(format string, args ...interface{}) { +func (sc *serverConn) vlogf(format string, args ...any) { if VerboseLogs { sc.logf(format, args...) } } -func (sc *serverConn) logf(format string, args ...interface{}) { +func (sc *serverConn) logf(format string, args ...any) { if lg := sc.hs.ErrorLog(); lg != nil { lg.Printf(format, args...) } else { @@ -721,7 +722,7 @@ func isClosedConnError(err error) bool { return false } -func (sc *serverConn) condlogf(err error, format string, args ...interface{}) { +func (sc *serverConn) condlogf(err error, format string, args ...any) { if err == nil { return } @@ -1042,7 +1043,7 @@ func (sc *serverConn) onIdleTimer() { sc.sendServeMsg(idleTimerMsg) } func (sc *serverConn) onReadIdleTimer() { sc.sendServeMsg(readIdleTimerMsg) } func (sc *serverConn) onShutdownTimer() { sc.sendServeMsg(shutdownTimerMsg) } -func (sc *serverConn) sendServeMsg(msg interface{}) { +func (sc *serverConn) sendServeMsg(msg any) { sc.serveG.checkNotOn() // NOT select { case sc.serveMsgCh <- msg: @@ -1087,7 +1088,7 @@ func (sc *serverConn) readPreface() error { } var writeDataPool = sync.Pool{ - New: func() interface{} { return new(writeData) }, + New: func() any { return new(writeData) }, } // writeDataFromHandler writes DATA response frames from a handler on @@ -2596,7 +2597,7 @@ func (rws *responseWriterState) declareTrailer(k string) { rws.conn.logf("ignoring invalid trailer %q", k) return } - if !strSliceContains(rws.trailers, k) { + if !slices.Contains(rws.trailers, k) { rws.trailers = append(rws.trailers, k) } } @@ -2759,9 +2760,7 @@ func (rws *responseWriterState) promoteUndeclaredTrailers() { } if len(rws.trailers) > 1 { - sorter := sorterPool.Get().(*sorter) - sorter.SortStrings(rws.trailers) - sorterPool.Put(sorter) + slices.Sort(rws.trailers) } } @@ -3206,7 +3205,7 @@ func foreachHeaderElement(v string, fn func(string)) { fn(v) return } - for _, f := range strings.Split(v, ",") { + for f := range strings.SplitSeq(v, ",") { if f = textproto.TrimString(f); f != "" { fn(f) } diff --git a/src/net/http/internal/http2/server_push_test.go b/src/net/http/internal/http2/server_push_test.go index 48a33b2a63..956fadb7bf 100644 --- a/src/net/http/internal/http2/server_push_test.go +++ b/src/net/http/internal/http2/server_push_test.go @@ -112,7 +112,7 @@ func testServer_Push_Success(t testing.TB) { // Send one request, which should push two responses. st.greet() getSlash(st) - for k := 0; k < 3; k++ { + for k := range 3 { select { case <-time.After(2 * time.Second): t.Errorf("timeout waiting for handler %d to finish", k) @@ -277,7 +277,7 @@ func testServer_Push_SuccessNoRace(t testing.TB) { // Send one request, which should push one response. st.greet() getSlash(st) - for k := 0; k < 2; k++ { + for k := range 2 { select { case <-time.After(2 * time.Second): t.Errorf("timeout waiting for handler %d to finish", k) @@ -543,7 +543,7 @@ func testServer_Push_Underflow(t testing.TB) { // Send several requests. st.greet() const numRequests = 4 - for i := 0; i < numRequests; i++ { + for i := range numRequests { st.writeHeaders(HeadersFrameParam{ StreamID: uint32(1 + i*2), // clients send odd numbers BlockFragment: st.encodeHeader(), diff --git a/src/net/http/internal/http2/server_test.go b/src/net/http/internal/http2/server_test.go index 85f93947c9..d9fd66f99c 100644 --- a/src/net/http/internal/http2/server_test.go +++ b/src/net/http/internal/http2/server_test.go @@ -119,7 +119,7 @@ func (w twriter) Write(p []byte) (n int, err error) { return len(p), nil } -func newTestServer(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *httptest.Server { +func newTestServer(t testing.TB, handler http.HandlerFunc, opts ...any) *httptest.Server { t.Helper() if handler == nil { handler = func(w http.ResponseWriter, req *http.Request) {} @@ -173,7 +173,7 @@ var optQuiet = func(server *http.Server) { server.ErrorLog = log.New(io.Discard, "", 0) } -func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester { +func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...any) *serverTester { t.Helper() h1server := &http.Server{} @@ -436,7 +436,7 @@ func (st *serverTester) greetAndCheckSettings(checkSetting func(s Setting) error var gotSettingsAck bool var gotWindowUpdate bool - for i := 0; i < 2; i++ { + for range 2 { f := st.readFrame() if f == nil { st.t.Fatal("wanted a settings ACK and window update, got none") @@ -1218,7 +1218,7 @@ func testServer_MaxQueuedControlFrames(t testing.TB) { // Send maxQueuedControlFrames pings, plus a few extra // to account for ones that enter the server's write buffer. const extraPings = 2 - for i := 0; i < MaxQueuedControlFrames+extraPings; i++ { + for range MaxQueuedControlFrames + extraPings { pingData := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} st.fr.WritePing(false, pingData) } @@ -1230,7 +1230,7 @@ func testServer_MaxQueuedControlFrames(t testing.TB) { st.advance(GoAwayTimeout) // Some frames may have persisted in the server's buffers. - for i := 0; i < 10; i++ { + for range 10 { if st.readFrame() == nil { break } @@ -1925,7 +1925,6 @@ func TestServerRejectsContentLengthWithSignNewRequests(t *testing.T) { } for _, tt := range tests { - tt := tt synctestSubtest(t, tt.name, func(t testing.TB) { writeReq := func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ @@ -2404,7 +2403,7 @@ func testServer_Rejects_Too_Many_Streams(t testing.TB) { }) } var calls []*serverHandlerCall - for i := 0; i < DefaultMaxStreams; i++ { + for range DefaultMaxStreams { sendReq(streamID()) calls = append(calls, st.nextHandlerCall()) } @@ -2451,7 +2450,7 @@ func TestServer_Response_ManyHeaders_With_Continuation(t *testing.T) { func testServer_Response_ManyHeaders_With_Continuation(t testing.TB) { testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { h := w.Header() - for i := 0; i < 5000; i++ { + for i := range 5000 { h.Set(fmt.Sprintf("x-header-%d", i), fmt.Sprintf("x-value-%d", i)) } return nil @@ -2526,10 +2525,10 @@ func testServer_NoCrash_HandlerClose_Then_ClientClose(t testing.TB) { // previously. var ( panMu sync.Mutex - panicVal interface{} + panicVal any ) - SetTestHookOnPanic(t, func(sc *ServerConn, pv interface{}) bool { + SetTestHookOnPanic(t, func(sc *ServerConn, pv any) bool { panMu.Lock() panicVal = pv panMu.Unlock() @@ -3544,7 +3543,7 @@ func testIssue20704Race(t testing.TB) { ) ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) { - for i := 0; i < itemCount; i++ { + for range itemCount { _, err := w.Write(make([]byte, itemSize)) if err != nil { return @@ -3559,7 +3558,7 @@ func testIssue20704Race(t testing.TB) { defer tr.CloseIdleConnections() cl := &http.Client{Transport: tr} - for i := 0; i < 1000; i++ { + for range 1000 { resp, err := cl.Get(ts.URL) if err != nil { t.Fatal(err) @@ -3792,7 +3791,7 @@ func TestContentEncodingNoSniffing(t *testing.T) { // setting Content-Encoding as an interface instead of a string // directly, so as to differentiate between 3 states: // unset, empty string "" and set string "foo/bar". - contentEncoding interface{} + contentEncoding any wantContentType string } @@ -4271,7 +4270,7 @@ func testServerMaxHandlerGoroutines(t testing.TB) { // Reset them all, but only after the handler goroutines have started. var stops []chan bool streamID := uint32(1) - for i := 0; i < maxHandlers; i++ { + for range maxHandlers { st.writeHeaders(HeadersFrameParam{ StreamID: streamID, BlockFragment: st.encodeHeader(), @@ -4294,7 +4293,7 @@ func testServerMaxHandlerGoroutines(t testing.TB) { streamID += 2 // Start another two requests. Don't reset these. - for i := 0; i < 2; i++ { + for range 2 { st.writeHeaders(HeadersFrameParam{ StreamID: streamID, BlockFragment: st.encodeHeader(), @@ -4322,7 +4321,7 @@ func testServerMaxHandlerGoroutines(t testing.TB) { // Make a bunch more requests. // Eventually, the server tells us to go away. - for i := 0; i < 5*maxHandlers; i++ { + for range 5 * maxHandlers { st.writeHeaders(HeadersFrameParam{ StreamID: streamID, BlockFragment: st.encodeHeader(), @@ -4358,7 +4357,7 @@ func testServerContinuationFlood(t testing.TB) { BlockFragment: st.encodeHeader(), EndStream: true, }) - for i := 0; i < 1000; i++ { + for i := range 1000 { st.fr.WriteContinuation(1, false, st.encodeHeaderRaw( fmt.Sprintf("x-%v", i), "1234567890", )) @@ -4511,7 +4510,7 @@ func testServerWriteByteTimeout(t testing.TB) { }) // Read a few bytes, staying just under WriteByteTimeout. - for i := 0; i < 10; i++ { + for i := range 10 { st.advance(timeout - 1) if n, err := st.cc.Read(make([]byte, 1)); n != 1 || err != nil { t.Fatalf("read %v: %v, %v; want 1, nil", i, n, err) diff --git a/src/net/http/internal/http2/transport.go b/src/net/http/internal/http2/transport.go index 6caba5046a..1e6f4474e2 100644 --- a/src/net/http/internal/http2/transport.go +++ b/src/net/http/internal/http2/transport.go @@ -708,7 +708,7 @@ func (t *Transport) newTLSConfig(host string) *tls.Config { if t.TLSClientConfig != nil { *cfg = *t.TLSClientConfig.Clone() } - if !strSliceContains(cfg.NextProtos, NextProtoTLS) { + if !slices.Contains(cfg.NextProtos, NextProtoTLS) { cfg.NextProtos = append([]string{NextProtoTLS}, cfg.NextProtos...) } if cfg.ServerName == "" { @@ -1794,10 +1794,7 @@ var ( // Request.ContentLength+1, 512KB)). func (cs *clientStream) frameScratchBufferLen(maxFrameSize int) int { const max = 512 << 10 - n := int64(maxFrameSize) - if n > max { - n = max - } + n := min(int64(maxFrameSize), max) if cl := cs.reqBodyContentLength; cl != -1 && cl+1 < n { // Add an extra byte past the declared content-length to // give the caller's Request.Body io.Reader a chance to @@ -3066,21 +3063,21 @@ var ( errRequestHeaderListSize = httpcommon.ErrRequestHeaderListSize ) -func (cc *ClientConn) logf(format string, args ...interface{}) { +func (cc *ClientConn) logf(format string, args ...any) { cc.t.logf(format, args...) } -func (cc *ClientConn) vlogf(format string, args ...interface{}) { +func (cc *ClientConn) vlogf(format string, args ...any) { cc.t.vlogf(format, args...) } -func (t *Transport) vlogf(format string, args ...interface{}) { +func (t *Transport) vlogf(format string, args ...any) { if VerboseLogs { t.logf(format, args...) } } -func (t *Transport) logf(format string, args ...interface{}) { +func (t *Transport) logf(format string, args ...any) { log.Printf(format, args...) } @@ -3089,15 +3086,6 @@ type missingBody struct{} func (missingBody) Close() error { return nil } func (missingBody) Read([]byte) (int, error) { return 0, io.ErrUnexpectedEOF } -func strSliceContains(ss []string, s string) bool { - for _, v := range ss { - if v == s { - return true - } - } - return false -} - type erringRoundTripper struct{ err error } func (rt erringRoundTripper) RoundTripErr() error { return rt.err } diff --git a/src/net/http/internal/http2/transport_test.go b/src/net/http/internal/http2/transport_test.go index 8f1a589624..ebbba817ff 100644 --- a/src/net/http/internal/http2/transport_test.go +++ b/src/net/http/internal/http2/transport_test.go @@ -123,7 +123,7 @@ func TestIdleConnTimeout(t *testing.T) { tr.IdleConnTimeout = test.idleConnTimeout }) var tc *testClientConn - for i := 0; i < 3; i++ { + for i := range 3 { req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) rt := tt.roundTrip(req) @@ -413,7 +413,7 @@ func testTransportGetGotConnHooks(t *testing.T, useClient bool) { getConns int32 gotConns int32 ) - for i := 0; i < 2; i++ { + for i := range 2 { trace := &httptrace.ClientTrace{ GetConn: func(hostport string) { atomic.AddInt32(&getConns, 1) @@ -1373,7 +1373,7 @@ func testTransportChecksResponseHeaderListSize(t testing.TB) { hdr := []string{":status", "200"} large := strings.Repeat("a", 1<<10) - for i := 0; i < 5042; i++ { + for range 5042 { hdr = append(hdr, large, large) } hbf := tc.makeHeaderBlockFragment(hdr...) @@ -1571,7 +1571,7 @@ func TestTransportDisableKeepAlives_Concurrency(t *testing.T) { c := &http.Client{Transport: tr} var reqs sync.WaitGroup const N = 20 - for i := 0; i < N; i++ { + for i := range N { reqs.Add(1) if i == N-1 { // For the final request, try to make all the @@ -1877,7 +1877,6 @@ func TestTransportRejectsContentLengthWithSign(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Length", tt.cl[0]) @@ -2464,7 +2463,7 @@ func testTransportBodyDoubleEndStream(t testing.TB) { tr := newTransport(t) - for i := 0; i < 2; i++ { + for i := range 2 { req, _ := http.NewRequest("POST", ts.URL, byteAndEOFReader('a')) req.ContentLength = 1 res, err := tr.RoundTrip(req) @@ -2658,7 +2657,7 @@ func TestTransportCancelDataResponseRace(t *testing.T) { io.WriteString(w, msg) return } - for i := 0; i < 50; i++ { + for i := range 50 { io.WriteString(w, "Some data.") w.(http.Flusher).Flush() if i == 2 { @@ -2795,7 +2794,7 @@ func testTransportPingWhenReadingMultiplePings(t testing.TB) { ), }) - for i := 0; i < 5; i++ { + for range 5 { // No ping yet... time.Sleep(999 * time.Millisecond) if f := tc.readFrame(); f != nil { @@ -3157,7 +3156,7 @@ func TestTransportRequestsLowServerLimit(t *testing.T) { } const reqCount = 3 - for i := 0; i < reqCount; i++ { + for range reqCount { req, err := http.NewRequest("GET", ts.URL, nil) if err != nil { t.Fatal(err) @@ -3196,7 +3195,7 @@ func testTransportRequestsStallAtServerLimit(t *testing.T) { // Start maxConcurrent+2 requests. // The server does not respond to any of them yet. var rts []*testRoundTrip - for k := 0; k < maxConcurrent+2; k++ { + for k := range maxConcurrent + 2 { req, _ := http.NewRequest("GET", fmt.Sprintf("https://dummy.tld/%d", k), nil) if k == maxConcurrent { req.Cancel = cancelClientRequest @@ -3378,7 +3377,7 @@ func benchSimpleRoundTrip(b *testing.B, nReqHeaders, nResHeader int) { b.ReportAllocs() ts := newTestServer(b, func(w http.ResponseWriter, r *http.Request) { - for i := 0; i < nResHeader; i++ { + for i := range nResHeader { name := fmt.Sprint("A-", i) w.Header().Set(name, "*") } @@ -3393,7 +3392,7 @@ func benchSimpleRoundTrip(b *testing.B, nReqHeaders, nResHeader int) { b.Fatal(err) } - for i := 0; i < nReqHeaders; i++ { + for i := range nReqHeaders { name := fmt.Sprint("A-", i) req.Header.Set(name, "*") } @@ -3496,7 +3495,7 @@ func benchLargeDownloadRoundTrip(b *testing.B, frameSize uint32) { w.Header().Set("Content-Length", strconv.Itoa(transferSize)) w.Header().Set("Content-Transfer-Encoding", "binary") var data [1024 * 1024]byte - for i := 0; i < transferSize/(1024*1024); i++ { + for range transferSize / (1024 * 1024) { w.Write(data[:]) } }, optQuiet, @@ -3922,7 +3921,7 @@ func TestTransportBodyRewindRace(t *testing.T) { var wg sync.WaitGroup wg.Add(clients) - for i := 0; i < clients; i++ { + for range clients { req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString("abcdef")) if err != nil { t.Fatalf("unexpected new request error: %v", err) @@ -4164,10 +4163,8 @@ func TestTransportFrameBufferReuse(t *testing.T) { var wg sync.WaitGroup defer wg.Wait() - for i := 0; i < 10; i++ { - wg.Add(1) - go func() { - defer wg.Done() + for range 10 { + wg.Go(func() { req, err := http.NewRequest("POST", ts.URL, strings.NewReader(filler)) if err != nil { t.Error(err) @@ -4187,7 +4184,7 @@ func TestTransportFrameBufferReuse(t *testing.T) { if res != nil && res.Body != nil { res.Body.Close() } - }() + }) } } @@ -4232,7 +4229,6 @@ func TestTransportBlockingRequestWrite(t *testing.T) { return req, err }, }} { - test := test t.Run(test.name, func(t *testing.T) { ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) { if v := r.Header.Get("Big"); v != "" && v != filler { @@ -4880,8 +4876,7 @@ func TestDialRaceResumesDial(t *testing.T) { ctx1, cancel1 := context.WithCancel(context.Background()) defer cancel1() req1 := req.WithContext(ctx1) - ctx2, cancel2 := context.WithCancel(context.Background()) - defer cancel2() + ctx2 := t.Context() req2 := req.WithContext(ctx2) errCh := make(chan error) go func() { @@ -4994,7 +4989,7 @@ func TestIssue67671(t *testing.T) { tr.Protocols = protocols("h2c") req, _ := http.NewRequest("GET", ts.URL, nil) req.Close = true - for i := 0; i < 2; i++ { + for range 2 { res, err := tr.RoundTrip(req) if err != nil { t.Fatal(err) @@ -5289,7 +5284,7 @@ func testTransportConnBecomesUnresponsive(t testing.TB) { // Send more requests. // None receive a response. // Each is canceled. - for i := 0; i < maxConcurrent; i++ { + for i := range maxConcurrent { t.Logf("request %v receives no response and is canceled", i) ctx, cancel := context.WithCancel(context.Background()) req := Must(http.NewRequestWithContext(ctx, "GET", "https://dummy.tld/", nil)) diff --git a/src/net/http/internal/http2/writesched.go b/src/net/http/internal/http2/writesched.go index 7de27be525..883c4ddc0d 100644 --- a/src/net/http/internal/http2/writesched.go +++ b/src/net/http/internal/http2/writesched.go @@ -115,10 +115,7 @@ func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteReque } // Might need to split after applying limits. - allowed := wr.stream.flow.available() - if n < allowed { - allowed = n - } + allowed := min(n, wr.stream.flow.available()) if wr.stream.sc.maxFrameSize < allowed { allowed = wr.stream.sc.maxFrameSize } diff --git a/src/net/http/internal/http2/writesched_priority_rfc7540.go b/src/net/http/internal/http2/writesched_priority_rfc7540.go index 7803a9261b..6828b733ae 100644 --- a/src/net/http/internal/http2/writesched_priority_rfc7540.go +++ b/src/net/http/internal/http2/writesched_priority_rfc7540.go @@ -5,9 +5,10 @@ package http2 import ( + "cmp" "fmt" "math" - "sort" + "slices" ) // RFC 7540, Section 5.3.5: the default weight is 16. @@ -199,7 +200,19 @@ func (n *priorityNodeRFC7540) walkReadyInOrder(openParent bool, tmp *[]*priority *tmp = append(*tmp, n.kids) n.kids.setParent(nil) } - sort.Sort(sortPriorityNodeSiblingsRFC7540(*tmp)) + slices.SortFunc(*tmp, func(i, k *priorityNodeRFC7540) int { + // Prefer the subtree that has sent fewer bytes relative to its weight. + // See sections 5.3.2 and 5.3.4. + wi, bi := float64(i.weight)+1, float64(i.subtreeBytes) + wk, bk := float64(k.weight)+1, float64(k.subtreeBytes) + if bi == 0 && bk == 0 { + return cmp.Compare(wk, wi) + } + if bk == 0 { + return 0 + } + return cmp.Compare(bi/bk, wi/wk) + }) for i := len(*tmp) - 1; i >= 0; i-- { (*tmp)[i].setParent(n) // setParent inserts at the head of n.kids } @@ -211,24 +224,6 @@ func (n *priorityNodeRFC7540) walkReadyInOrder(openParent bool, tmp *[]*priority return false } -type sortPriorityNodeSiblingsRFC7540 []*priorityNodeRFC7540 - -func (z sortPriorityNodeSiblingsRFC7540) Len() int { return len(z) } -func (z sortPriorityNodeSiblingsRFC7540) Swap(i, k int) { z[i], z[k] = z[k], z[i] } -func (z sortPriorityNodeSiblingsRFC7540) Less(i, k int) bool { - // Prefer the subtree that has sent fewer bytes relative to its weight. - // See sections 5.3.2 and 5.3.4. - wi, bi := float64(z[i].weight)+1, float64(z[i].subtreeBytes) - wk, bk := float64(z[k].weight)+1, float64(z[k].subtreeBytes) - if bi == 0 && bk == 0 { - return wi >= wk - } - if bk == 0 { - return false - } - return bi/bk <= wi/wk -} - type priorityWriteSchedulerRFC7540 struct { // root is the root of the priority tree, where root.id = 0. // The root queues control frames that are not associated with any stream. diff --git a/src/net/http/internal/http2/writesched_roundrobin_test.go b/src/net/http/internal/http2/writesched_roundrobin_test.go index 032b2bc6cd..f86bc12092 100644 --- a/src/net/http/internal/http2/writesched_roundrobin_test.go +++ b/src/net/http/internal/http2/writesched_roundrobin_test.go @@ -33,12 +33,12 @@ func TestRoundRobinScheduler(t *testing.T) { ws.Push(wr) } const controlFrames = 2 - for i := 0; i < controlFrames; i++ { + for range controlFrames { ws.Push(makeWriteNonStreamRequest()) } // We should get the control frames first. - for i := 0; i < controlFrames; i++ { + for range controlFrames { wr, ok := ws.Pop() if !ok || wr.StreamID() != 0 { t.Fatalf("wr.Pop() = stream %v, %v; want 0, true", wr.StreamID(), ok) |
