net/http/httptest: close conns in StateNew on Server close

This part got dropped when we were debating between two solutions
in https://golang.org/cl/15151

Fixes #13032

Change-Id: I820b94f6c0c102ccf9342abf957328ea01f49a26
Reviewed-on: https://go-review.googlesource.com/16313
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
index b5f1149..4a45b2b 100644
--- a/src/net/http/httptest/server.go
+++ b/src/net/http/httptest/server.go
@@ -150,7 +150,25 @@
 		s.Listener.Close()
 		s.Config.SetKeepAlivesEnabled(false)
 		for c, st := range s.conns {
-			if st == http.StateIdle {
+			// Force-close any idle connections (those between
+			// requests) and new connections (those which connected
+			// but never sent a request). StateNew connections are
+			// super rare and have only been seen (in
+			// previously-flaky tests) in the case of
+			// socket-late-binding races from the http Client
+			// dialing this server and then getting an idle
+			// connection before the dial completed.  There is thus
+			// a connected connection in StateNew with no
+			// associated Request. We only close StateIdle and
+			// StateNew because they're not doing anything. It's
+			// possible StateNew is about to do something in a few
+			// milliseconds, but a previous CL to check again in a
+			// few milliseconds wasn't liked (early versions of
+			// https://golang.org/cl/15151) so now we just
+			// forcefully close StateNew. The docs for Server.Close say
+			// we wait for "oustanding requests", so we don't close things
+			// in StateActive.
+			if st == http.StateIdle || st == http.StateNew {
 				s.closeConn(c)
 			}
 		}
diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go
index 90901ce..6ffc671 100644
--- a/src/net/http/httptest/server_test.go
+++ b/src/net/http/httptest/server_test.go
@@ -5,7 +5,9 @@
 package httptest
 
 import (
+	"bufio"
 	"io/ioutil"
+	"net"
 	"net/http"
 	"testing"
 )
@@ -54,3 +56,31 @@
 		t.Fatalf("Unexected response after close: %v, %v, %s", res.Status, res.Header, body)
 	}
 }
+
+func TestServerCloseBlocking(t *testing.T) {
+	ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("hello"))
+	}))
+	dial := func() net.Conn {
+		c, err := net.Dial("tcp", ts.Listener.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		return c
+	}
+
+	// Keep one connection in StateNew (connected, but not sending anything)
+	cnew := dial()
+	defer cnew.Close()
+
+	// Keep one connection in StateIdle (idle after a request)
+	cidle := dial()
+	defer cidle.Close()
+	cidle.Write([]byte("HEAD / HTTP/1.1\r\nHost: foo\r\n\r\n"))
+	_, err := http.ReadResponse(bufio.NewReader(cidle), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ts.Close() // test we don't hang here forever.
+}