mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 16:50:58 +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
	
	 Damien Neil
						Damien Neil