diff options
| -rw-r--r-- | api/next/67813.txt | 1 | ||||
| -rw-r--r-- | doc/next/6-stdlib/99-minor/net/http/67813.md | 4 | ||||
| -rw-r--r-- | src/net/http/http.go | 15 | ||||
| -rw-r--r-- | src/net/http/transport_dial_test.go | 39 |
4 files changed, 57 insertions, 2 deletions
diff --git a/api/next/67813.txt b/api/next/67813.txt new file mode 100644 index 0000000000..b420a141e1 --- /dev/null +++ b/api/next/67813.txt @@ -0,0 +1 @@ +pkg net/http, type HTTP2Config struct, StrictMaxConcurrentRequests bool #67813 diff --git a/doc/next/6-stdlib/99-minor/net/http/67813.md b/doc/next/6-stdlib/99-minor/net/http/67813.md new file mode 100644 index 0000000000..74b8c7644f --- /dev/null +++ b/doc/next/6-stdlib/99-minor/net/http/67813.md @@ -0,0 +1,4 @@ +The new +[HTTP2Config.StrictMaxConcurrentRequests](/pkg/net/http#HTTP2Config.StrictMaxConcurrentRequests) +field controls whether a new connection should be opened +if an existing HTTP/2 connection has exceeded its stream limit. diff --git a/src/net/http/http.go b/src/net/http/http.go index 0f9165bf03..e7959fa3b6 100644 --- a/src/net/http/http.go +++ b/src/net/http/http.go @@ -235,10 +235,23 @@ type Pusher interface { // both [Transport] and [Server]. type HTTP2Config struct { // MaxConcurrentStreams optionally specifies the number of - // concurrent streams that a peer may have open at a time. + // concurrent streams that a client may have open at a time. // If zero, MaxConcurrentStreams defaults to at least 100. + // + // This parameter only applies to Servers. MaxConcurrentStreams int + // StrictMaxConcurrentRequests controls whether an HTTP/2 server's + // concurrency limit should be respected across all connections + // to that server. + // If true, new requests sent when a connection's concurrency limit + // has been exceeded will block until an existing request completes. + // If false, an additional connection will be opened if all + // existing connections are at their limit. + // + // This parameter only applies to Transports. + StrictMaxConcurrentRequests bool + // MaxDecoderHeaderTableSize optionally specifies an upper limit for the // size of the header compression table used for decoding headers sent // by the peer. diff --git a/src/net/http/transport_dial_test.go b/src/net/http/transport_dial_test.go index d7f7a3d539..086039ece9 100644 --- a/src/net/http/transport_dial_test.go +++ b/src/net/http/transport_dial_test.go @@ -59,7 +59,7 @@ func TestTransportPoolConnCannotReuseConnectionInUse(t *testing.T) { // When an HTTP/2 connection is at its stream limit // a new request is made on a new connection. -func TestTransportPoolConnHTTP2OverStreamLimit(t *testing.T) { +func testTransportPoolConnHTTP2NoStrictMaxConcurrentRequests(t *testing.T) { synctest.Test(t, func(t *testing.T) { dt := newTransportDialTester(t, http2Mode, func(srv *http.Server) { srv.HTTP2 = &http.HTTP2Config{ @@ -100,6 +100,43 @@ func TestTransportPoolConnHTTP2OverStreamLimit(t *testing.T) { }) } +// When an HTTP/2 connection is at its stream limit +// and StrictMaxConcurrentRequests = true, +// a new request waits for a slot on the existing connection. +func TestTransportPoolConnHTTP2StrictMaxConcurrentRequests(t *testing.T) { + t.Skip("skipped until h2_bundle.go includes support for StrictMaxConcurrentRequests") + + synctest.Test(t, func(t *testing.T) { + dt := newTransportDialTester(t, http2Mode, func(srv *http.Server) { + srv.HTTP2.MaxConcurrentStreams = 2 + }, func(tr *http.Transport) { + tr.HTTP2 = &http.HTTP2Config{ + StrictMaxConcurrentRequests: true, + } + }) + + // First request dials an HTTP/2 connection. + rt1 := dt.roundTrip() + c1 := dt.wantDial() + c1.finish(nil) + rt1.wantDone(c1, "HTTP/2.0") + + // Second request uses the existing connection. + rt2 := dt.roundTrip() + rt2.wantDone(c1, "HTTP/2.0") + + // Third request blocks waiting for a slot on the existing connection. + rt3 := dt.roundTrip() + + // First request finishing unblocks the thirrd. + rt1.finish() + rt3.wantDone(c1, "HTTP/2.0") + + rt2.finish() + rt3.finish() + }) +} + // A new request made while an HTTP/2 dial is in progress will start a second dial. func TestTransportPoolConnHTTP2Startup(t *testing.T) { synctest.Test(t, func(t *testing.T) { |
