mirror of
https://github.com/golang/go.git
synced 2025-10-19 19:13:18 +00:00
net/http: add onClose hook to fake net listener
Avoids a race condition: If we set an onClose hook on a conn created by a listener, then setting the hook can race with the connection closing. Change-Id: Ibadead3abbe4335d41f1e2cf84f4696fe98166b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/658655 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jonathan Amsterdam <jba@google.com> Auto-Submit: Damien Neil <dneil@google.com>
This commit is contained in:
parent
5916bc5b57
commit
a17c092c2c
2 changed files with 10 additions and 7 deletions
|
@ -36,6 +36,7 @@ type fakeNetListener struct {
|
||||||
locPort uint16
|
locPort uint16
|
||||||
|
|
||||||
onDial func() // called when making a new connection
|
onDial func() // called when making a new connection
|
||||||
|
onClose func(*fakeNetConn) // called when closing a connection
|
||||||
|
|
||||||
trackConns bool // set this to record all created conns
|
trackConns bool // set this to record all created conns
|
||||||
conns []*fakeNetConn
|
conns []*fakeNetConn
|
||||||
|
@ -65,6 +66,8 @@ func (li *fakeNetListener) connect() *fakeNetConn {
|
||||||
locAddr := netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), li.locPort)
|
locAddr := netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), li.locPort)
|
||||||
li.locPort++
|
li.locPort++
|
||||||
c0, c1 := fakeNetPipe(li.addr, locAddr)
|
c0, c1 := fakeNetPipe(li.addr, locAddr)
|
||||||
|
c0.onClose = li.onClose
|
||||||
|
c1.onClose = li.onClose
|
||||||
li.queue = append(li.queue, c0)
|
li.queue = append(li.queue, c0)
|
||||||
if li.trackConns {
|
if li.trackConns {
|
||||||
li.conns = append(li.conns, c0)
|
li.conns = append(li.conns, c0)
|
||||||
|
@ -124,7 +127,7 @@ type fakeNetConn struct {
|
||||||
// peer is the other endpoint.
|
// peer is the other endpoint.
|
||||||
peer *fakeNetConn
|
peer *fakeNetConn
|
||||||
|
|
||||||
onClose func() // called when closing
|
onClose func(*fakeNetConn) // called when closing
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read reads data from the connection.
|
// Read reads data from the connection.
|
||||||
|
@ -167,7 +170,7 @@ func (c *fakeNetConn) IsClosedByPeer() bool {
|
||||||
// Close closes the connection.
|
// Close closes the connection.
|
||||||
func (c *fakeNetConn) Close() error {
|
func (c *fakeNetConn) Close() error {
|
||||||
if c.onClose != nil {
|
if c.onClose != nil {
|
||||||
c.onClose()
|
c.onClose(c)
|
||||||
}
|
}
|
||||||
// Local half of the conn is now closed.
|
// Local half of the conn is now closed.
|
||||||
c.loc.lock()
|
c.loc.lock()
|
||||||
|
|
|
@ -4250,6 +4250,10 @@ func testTransportIdleConnRacesRequest(t testing.TB, mode testMode) {
|
||||||
cst.li.onDial = func() {
|
cst.li.onDial = func() {
|
||||||
<-dialc
|
<-dialc
|
||||||
}
|
}
|
||||||
|
closec := make(chan struct{})
|
||||||
|
cst.li.onClose = func(*fakeNetConn) {
|
||||||
|
<-closec
|
||||||
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
req1c := make(chan error)
|
req1c := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -4279,10 +4283,6 @@ func testTransportIdleConnRacesRequest(t testing.TB, mode testMode) {
|
||||||
//
|
//
|
||||||
// First: Wait for IdleConnTimeout. The net.Conn.Close blocks.
|
// First: Wait for IdleConnTimeout. The net.Conn.Close blocks.
|
||||||
synctest.Wait()
|
synctest.Wait()
|
||||||
closec := make(chan struct{})
|
|
||||||
cst.li.conns[0].peer.onClose = func() {
|
|
||||||
<-closec
|
|
||||||
}
|
|
||||||
time.Sleep(timeout)
|
time.Sleep(timeout)
|
||||||
synctest.Wait()
|
synctest.Wait()
|
||||||
// Make a request, which will use a new connection (since the existing one is closing).
|
// Make a request, which will use a new connection (since the existing one is closing).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue