diff options
| author | Damien Neil <dneil@google.com> | 2024-09-25 11:10:07 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-09-26 16:14:14 -0700 |
| commit | 3a5df9d2b20c0f059c463b5d51e89be17a2c685b (patch) | |
| tree | 8163d083beaf4b1f5683fb3ea56ed97bff67f39a /src/net/http | |
| parent | 16be34df02ba073456e5f31203549165585f3e6c (diff) | |
| download | go-3a5df9d2b20c0f059c463b5d51e89be17a2c685b.tar.xz | |
net/http: add HTTP2Config.StrictMaxConcurrentRequests
Add a field to HTTP2Config controlling how we behave when an HTTP/2
connection reaches its concurrency limit.
This field will have no effect until golang.org/x/net/http2 is
updated to make use of it, and h2_bundle.go is updated with the
new http2 package.
For #67813
Change-Id: Ic72a0986528abb21649f28e9fe7cf6e1236b388d
Reviewed-on: https://go-review.googlesource.com/c/go/+/615875
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Nicholas Husin <nsh@golang.org>
Reviewed-by: Nicholas Husin <husin@google.com>
Diffstat (limited to 'src/net/http')
| -rw-r--r-- | src/net/http/http.go | 15 | ||||
| -rw-r--r-- | src/net/http/transport_dial_test.go | 39 |
2 files changed, 52 insertions, 2 deletions
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) { |
