aboutsummaryrefslogtreecommitdiff
path: root/src/net/http
diff options
context:
space:
mode:
authorqiulaidongfeng <2645477756@qq.com>2026-03-13 23:43:05 +0800
committerNicholas Husin <nsh@golang.org>2026-03-23 12:27:43 -0700
commite1bc5cea825171f68f928686ed02a0d0abddd84c (patch)
treed3c98995c7dd19f19a2cb982170d28a9262007cd /src/net/http
parent224489f11c2e0b394e93980fc8292c52f60b18a8 (diff)
downloadgo-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')
-rw-r--r--src/net/http/internal/http2/client_conn_pool.go7
-rw-r--r--src/net/http/internal/http2/databuffer.go15
-rw-r--r--src/net/http/internal/http2/databuffer_test.go17
-rw-r--r--src/net/http/internal/http2/errors.go4
-rw-r--r--src/net/http/internal/http2/export_test.go2
-rw-r--r--src/net/http/internal/http2/frame.go12
-rw-r--r--src/net/http/internal/http2/frame_test.go20
-rw-r--r--src/net/http/internal/http2/gotrack.go2
-rw-r--r--src/net/http/internal/http2/gotrack_test.go2
-rw-r--r--src/net/http/internal/http2/http2.go21
-rw-r--r--src/net/http/internal/http2/http2_test.go7
-rw-r--r--src/net/http/internal/http2/server.go27
-rw-r--r--src/net/http/internal/http2/server_push_test.go6
-rw-r--r--src/net/http/internal/http2/server_test.go35
-rw-r--r--src/net/http/internal/http2/transport.go24
-rw-r--r--src/net/http/internal/http2/transport_test.go43
-rw-r--r--src/net/http/internal/http2/writesched.go5
-rw-r--r--src/net/http/internal/http2/writesched_priority_rfc7540.go35
-rw-r--r--src/net/http/internal/http2/writesched_roundrobin_test.go4
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)