Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http/httptest: Server.Close should also client connections #4436

Closed
bradfitz opened this issue Nov 25, 2012 · 5 comments
Closed

net/http/httptest: Server.Close should also client connections #4436

bradfitz opened this issue Nov 25, 2012 · 5 comments
Milestone

Comments

@bradfitz
Copy link
Contributor

From email discussions of the failure in
http://build.golang.org/log/6ff3bf8d00581f05902a4cf1af9b51555f12686e

TestServerContentType uses http.Get, which uses the default transport, which reuses TCP
keep-alive connections to the HTTP server, keyed on the (scheme, host, port, proxy). 
The previous test calling "defer ts.Close()" only closes the *listener* for
the previous test, not already-connected connections.  So if TestB comes along after
TestA is closed and TestB gets the same port number and calls Get, it might get a TCP
connection that's still connected to TestA's handler.

All of our tests do call ts.Close(), but few call
http://golang.org/pkg/net/http/httptest/#Server.CloseClientConnections .  I think
httptest.Close should call httptest.CloseClientConnections, and block waiting for those
to die.

And/or an httptest.Server should also make an *http.Client & Transport with its own
pool of connections for tests to use, rather than using the global http.Get function.
@bradfitz
Copy link
Contributor Author

Comment 1:

To test this, we can make httptest's private newLocalListener function always first try
to reuse the address of the most-recently-closed listener.  In practice, this will make
the net/http tests (which never run in parallel) always re-use the same address for all
tests.  This should cause tests to fail 100% of the time, as seen in failure above that
motivated this issue.
Then it'll be easy to verify the fix works, then we can undo the intentional address
reuse before submitting.

@bradfitz
Copy link
Contributor Author

Comment 2:

Yup, explicitly causing the port to be reused (as *BSD must do more often by default)
causes the net/http tests to be unhappy:
diff -r cda840e2befc src/pkg/net/http/httptest/server.go
--- a/src/pkg/net/http/httptest/server.go       Sun Nov 25 09:04:13 2012 -0800
+++ b/src/pkg/net/http/httptest/server.go       Sun Nov 25 11:38:01 2012 -0800
@@ -50,6 +50,8 @@
        return
 }
 
+var lastAddr = make(chan string, 1)
+
 func newLocalListener() net.Listener {
        if *serve != "" {
                l, err := net.Listen("tcp", *serve)
@@ -58,6 +60,19 @@
                }
                return l
        }
+
+       // Try to reuse the most-recently-closed address first, just to make
+       // port-reuse bugs stand out easier.
+       select {
+       case addr := <-lastAddr:
+               l, err := net.Listen("tcp", addr)
+               if err == nil {
+                       println("reused", addr)
+                       return l
+               }
+       default:
+       }
+
        l, err := net.Listen("tcp", "127.0.0.1:0")
        if err != nil {
                if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
@@ -153,7 +168,13 @@
 // Close shuts down the server and blocks until all outstanding
 // requests on this server have completed.
 func (s *Server) Close() {
+       addr := s.Listener.Addr().String()
        s.Listener.Close()
+       select {
+       case lastAddr <- addr:
+       default:
+       }
        s.wg.Wait()
 }

@bradfitz
Copy link
Contributor Author

Comment 3:

This issue was closed by revision f97bb12.

Status changed to Fixed.

@bradfitz
Copy link
Contributor Author

Comment 4:

Issue #4021 has been merged into this issue.

@bradfitz
Copy link
Contributor Author

Comment 5:

Issue #4021 has been merged into this issue.

@bradfitz bradfitz self-assigned this Nov 26, 2012
@rsc rsc added this to the Go1.1 milestone Apr 14, 2015
@rsc rsc removed the go1.1 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 24, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants