Skip to content

Commit 47a241f

Browse files
neildgopherbot
authored andcommitted
http2: make the error channel pool per-Server
Channels can't be shared across synctest bubbles, so a global pool causes panics when using an http2.Server in a bubble. Make the pool per-Server. A Server can't be shared across bubbles anyway (it contains channels) and outside of tests most programs will have a single Server. Fixes golang/go#75674 Change-Id: I966f985e1b9644bdf8ae81d9abb142d80320cc82 Reviewed-on: https://go-review.googlesource.com/c/net/+/708135 Auto-Submit: Nicholas Husin <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: Nicholas Husin <[email protected]> Reviewed-by: Nicholas Husin <[email protected]>
1 parent 51f657b commit 47a241f

File tree

3 files changed

+35
-28
lines changed

3 files changed

+35
-28
lines changed

http2/http2.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ var (
3434
VerboseLogs bool
3535
logFrameWrites bool
3636
logFrameReads bool
37-
inTests bool
3837

3938
// Enabling extended CONNECT by causes browsers to attempt to use
4039
// WebSockets-over-HTTP/2. This results in problems when the server's websocket

http2/http2_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ func condSkipFailingTest(t *testing.T) {
3030
}
3131

3232
func init() {
33-
inTests = true
3433
DebugGoroutines = true
3534
flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging")
3635
}

http2/server.go

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ type Server struct {
181181
type serverInternalState struct {
182182
mu sync.Mutex
183183
activeConns map[*serverConn]struct{}
184+
185+
// Pool of error channels. This is per-Server rather than global
186+
// because channels can't be reused across synctest bubbles.
187+
errChanPool sync.Pool
184188
}
185189

186190
func (s *serverInternalState) registerConn(sc *serverConn) {
@@ -212,6 +216,27 @@ func (s *serverInternalState) startGracefulShutdown() {
212216
s.mu.Unlock()
213217
}
214218

219+
// Global error channel pool used for uninitialized Servers.
220+
// We use a per-Server pool when possible to avoid using channels across synctest bubbles.
221+
var errChanPool = sync.Pool{
222+
New: func() any { return make(chan error, 1) },
223+
}
224+
225+
func (s *serverInternalState) getErrChan() chan error {
226+
if s == nil {
227+
return errChanPool.Get().(chan error) // Server used without calling ConfigureServer
228+
}
229+
return s.errChanPool.Get().(chan error)
230+
}
231+
232+
func (s *serverInternalState) putErrChan(ch chan error) {
233+
if s == nil {
234+
errChanPool.Put(ch) // Server used without calling ConfigureServer
235+
return
236+
}
237+
s.errChanPool.Put(ch)
238+
}
239+
215240
// ConfigureServer adds HTTP/2 support to a net/http Server.
216241
//
217242
// The configuration conf may be nil.
@@ -224,7 +249,10 @@ func ConfigureServer(s *http.Server, conf *Server) error {
224249
if conf == nil {
225250
conf = new(Server)
226251
}
227-
conf.state = &serverInternalState{activeConns: make(map[*serverConn]struct{})}
252+
conf.state = &serverInternalState{
253+
activeConns: make(map[*serverConn]struct{}),
254+
errChanPool: sync.Pool{New: func() any { return make(chan error, 1) }},
255+
}
228256
if h1, h2 := s, conf; h2.IdleTimeout == 0 {
229257
if h1.IdleTimeout != 0 {
230258
h2.IdleTimeout = h1.IdleTimeout
@@ -1124,33 +1152,14 @@ func (sc *serverConn) readPreface() error {
11241152
}
11251153
}
11261154

1127-
var errChanPool = sync.Pool{
1128-
New: func() interface{} { return make(chan error, 1) },
1129-
}
1130-
1131-
func getErrChan() chan error {
1132-
if inTests {
1133-
// Channels cannot be reused across synctest tests.
1134-
return make(chan error, 1)
1135-
} else {
1136-
return errChanPool.Get().(chan error)
1137-
}
1138-
}
1139-
1140-
func putErrChan(ch chan error) {
1141-
if !inTests {
1142-
errChanPool.Put(ch)
1143-
}
1144-
}
1145-
11461155
var writeDataPool = sync.Pool{
11471156
New: func() interface{} { return new(writeData) },
11481157
}
11491158

11501159
// writeDataFromHandler writes DATA response frames from a handler on
11511160
// the given stream.
11521161
func (sc *serverConn) writeDataFromHandler(stream *stream, data []byte, endStream bool) error {
1153-
ch := getErrChan()
1162+
ch := sc.srv.state.getErrChan()
11541163
writeArg := writeDataPool.Get().(*writeData)
11551164
*writeArg = writeData{stream.id, data, endStream}
11561165
err := sc.writeFrameFromHandler(FrameWriteRequest{
@@ -1182,7 +1191,7 @@ func (sc *serverConn) writeDataFromHandler(stream *stream, data []byte, endStrea
11821191
return errStreamClosed
11831192
}
11841193
}
1185-
putErrChan(ch)
1194+
sc.srv.state.putErrChan(ch)
11861195
if frameWriteDone {
11871196
writeDataPool.Put(writeArg)
11881197
}
@@ -2436,7 +2445,7 @@ func (sc *serverConn) writeHeaders(st *stream, headerData *writeResHeaders) erro
24362445
// waiting for this frame to be written, so an http.Flush mid-handler
24372446
// writes out the correct value of keys, before a handler later potentially
24382447
// mutates it.
2439-
errc = getErrChan()
2448+
errc = sc.srv.state.getErrChan()
24402449
}
24412450
if err := sc.writeFrameFromHandler(FrameWriteRequest{
24422451
write: headerData,
@@ -2448,7 +2457,7 @@ func (sc *serverConn) writeHeaders(st *stream, headerData *writeResHeaders) erro
24482457
if errc != nil {
24492458
select {
24502459
case err := <-errc:
2451-
putErrChan(errc)
2460+
sc.srv.state.putErrChan(errc)
24522461
return err
24532462
case <-sc.doneServing:
24542463
return errClientDisconnected
@@ -3129,7 +3138,7 @@ func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
31293138
method: opts.Method,
31303139
url: u,
31313140
header: cloneHeader(opts.Header),
3132-
done: getErrChan(),
3141+
done: sc.srv.state.getErrChan(),
31333142
}
31343143

31353144
select {
@@ -3146,7 +3155,7 @@ func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
31463155
case <-st.cw:
31473156
return errStreamClosed
31483157
case err := <-msg.done:
3149-
putErrChan(msg.done)
3158+
sc.srv.state.putErrChan(msg.done)
31503159
return err
31513160
}
31523161
}

0 commit comments

Comments
 (0)