t.Errorf("expected echo of size %d; got %d", handlerN, buf.Len())
}
}
+
+// Issue 48642: close accepted connection
+func TestServerCloseAccepted(t *testing.T) {
+ closed := 0
+ conn := &rwTestConn{
+ closeFunc: func() error {
+ closed++
+ return nil
+ },
+ }
+ ln := &oneConnListener{conn: conn}
+ var srv Server
+ // Use ConnContext to close server after connection is accepted but before it is tracked
+ srv.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
+ srv.Close()
+ return ctx
+ }
+ got := srv.Serve(ln)
+ if got != ErrServerClosed {
+ t.Errorf("Serve err = %v; want ErrServerClosed", got)
+ }
+ if closed != 1 {
+ t.Errorf("Connection expected to be closed")
+ }
+}
func (c *conn) setState(nc net.Conn, state ConnState, runHook bool) {
srv := c.server
switch state {
- case StateNew:
- srv.trackConn(c, true)
case StateHijacked, StateClosed:
- srv.trackConn(c, false)
+ srv.mu.Lock()
+ delete(srv.activeConn, c)
+ srv.mu.Unlock()
}
if state > 0xff || state < 0 {
panic("internal error")
}
tempDelay = 0
c := srv.newConn(rw)
+ if !srv.trackConn(c) {
+ rw.Close()
+ return ErrServerClosed
+ }
c.setState(c.rwc, StateNew, runHooks) // before Serve can return
go c.serve(connCtx)
}
return true
}
-func (s *Server) trackConn(c *conn, add bool) {
+// trackConn adds a connection to the set of tracked connections.
+// It reports whether the server is still up (not Shutdown or Closed).
+func (s *Server) trackConn(c *conn) bool {
s.mu.Lock()
defer s.mu.Unlock()
+ if s.shuttingDown() {
+ return false
+ }
if s.activeConn == nil {
s.activeConn = make(map[*conn]struct{})
}
- if add {
- s.activeConn[c] = struct{}{}
- } else {
- delete(s.activeConn, c)
- }
+ s.activeConn[c] = struct{}{}
+ return true
}
func (s *Server) idleTimeout() time.Duration {