Skip to content

Commit 3a5df9d

Browse files
neildgopherbot
authored andcommitted
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 golang#67813 Change-Id: Ic72a0986528abb21649f28e9fe7cf6e1236b388d Reviewed-on: https://go-review.googlesource.com/c/go/+/615875 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Damien Neil <[email protected]> Reviewed-by: Nicholas Husin <[email protected]> Reviewed-by: Nicholas Husin <[email protected]>
1 parent 16be34d commit 3a5df9d

File tree

4 files changed

+57
-2
lines changed

4 files changed

+57
-2
lines changed

api/next/67813.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pkg net/http, type HTTP2Config struct, StrictMaxConcurrentRequests bool #67813
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The new
2+
[HTTP2Config.StrictMaxConcurrentRequests](/pkg/net/http#HTTP2Config.StrictMaxConcurrentRequests)
3+
field controls whether a new connection should be opened
4+
if an existing HTTP/2 connection has exceeded its stream limit.

src/net/http/http.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,23 @@ type Pusher interface {
235235
// both [Transport] and [Server].
236236
type HTTP2Config struct {
237237
// MaxConcurrentStreams optionally specifies the number of
238-
// concurrent streams that a peer may have open at a time.
238+
// concurrent streams that a client may have open at a time.
239239
// If zero, MaxConcurrentStreams defaults to at least 100.
240+
//
241+
// This parameter only applies to Servers.
240242
MaxConcurrentStreams int
241243

244+
// StrictMaxConcurrentRequests controls whether an HTTP/2 server's
245+
// concurrency limit should be respected across all connections
246+
// to that server.
247+
// If true, new requests sent when a connection's concurrency limit
248+
// has been exceeded will block until an existing request completes.
249+
// If false, an additional connection will be opened if all
250+
// existing connections are at their limit.
251+
//
252+
// This parameter only applies to Transports.
253+
StrictMaxConcurrentRequests bool
254+
242255
// MaxDecoderHeaderTableSize optionally specifies an upper limit for the
243256
// size of the header compression table used for decoding headers sent
244257
// by the peer.

src/net/http/transport_dial_test.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func TestTransportPoolConnCannotReuseConnectionInUse(t *testing.T) {
5959

6060
// When an HTTP/2 connection is at its stream limit
6161
// a new request is made on a new connection.
62-
func TestTransportPoolConnHTTP2OverStreamLimit(t *testing.T) {
62+
func testTransportPoolConnHTTP2NoStrictMaxConcurrentRequests(t *testing.T) {
6363
synctest.Test(t, func(t *testing.T) {
6464
dt := newTransportDialTester(t, http2Mode, func(srv *http.Server) {
6565
srv.HTTP2 = &http.HTTP2Config{
@@ -100,6 +100,43 @@ func TestTransportPoolConnHTTP2OverStreamLimit(t *testing.T) {
100100
})
101101
}
102102

103+
// When an HTTP/2 connection is at its stream limit
104+
// and StrictMaxConcurrentRequests = true,
105+
// a new request waits for a slot on the existing connection.
106+
func TestTransportPoolConnHTTP2StrictMaxConcurrentRequests(t *testing.T) {
107+
t.Skip("skipped until h2_bundle.go includes support for StrictMaxConcurrentRequests")
108+
109+
synctest.Test(t, func(t *testing.T) {
110+
dt := newTransportDialTester(t, http2Mode, func(srv *http.Server) {
111+
srv.HTTP2.MaxConcurrentStreams = 2
112+
}, func(tr *http.Transport) {
113+
tr.HTTP2 = &http.HTTP2Config{
114+
StrictMaxConcurrentRequests: true,
115+
}
116+
})
117+
118+
// First request dials an HTTP/2 connection.
119+
rt1 := dt.roundTrip()
120+
c1 := dt.wantDial()
121+
c1.finish(nil)
122+
rt1.wantDone(c1, "HTTP/2.0")
123+
124+
// Second request uses the existing connection.
125+
rt2 := dt.roundTrip()
126+
rt2.wantDone(c1, "HTTP/2.0")
127+
128+
// Third request blocks waiting for a slot on the existing connection.
129+
rt3 := dt.roundTrip()
130+
131+
// First request finishing unblocks the thirrd.
132+
rt1.finish()
133+
rt3.wantDone(c1, "HTTP/2.0")
134+
135+
rt2.finish()
136+
rt3.finish()
137+
})
138+
}
139+
103140
// A new request made while an HTTP/2 dial is in progress will start a second dial.
104141
func TestTransportPoolConnHTTP2Startup(t *testing.T) {
105142
synctest.Test(t, func(t *testing.T) {

0 commit comments

Comments
 (0)