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 races with Serve #12789
Comments
I think this is a dup of #12781 ? |
You quote two lines of that method, but not the immediately-following lines: s.CloseClientConnections()
if t, ok := http.DefaultTransport.(*http.Transport); ok {
t.CloseIdleConnections()
} And then claim the method does nothing to existing connections? |
I was imprecise: it doesn't do anything to stop them before calling Wait, which is what matters for the race. |
And yes, this looks like the same underlying issue as #12781. |
CL https://golang.org/cl/15151 mentions this issue. |
See https://go-review.googlesource.com/#/c/15047/, which works around this race in one particular instance - you can reproduce this error prior to that change by running context/ctxhttp/ctxhttp_test under the race detector.
Close makes this sequence of calls:
The call to
s.Listener.Close
prevents new connections from being established, but it does not do anything to stop existing connections.Calling Start on the server calls
(*Server).wrapHandler
, which injects awaitGroupHandler
. ItsServeHTTP
method callss.wg.Add
:ServeHTTP is called after the listener's
Accept
has already returned, soClose
may already have been called in the meantime and the call toh.s.wg.Add
races with thes.wg.Wait
there.I believe that the simplest fix (which is unfortunately not all that simple) is to wrap the
net.Listener
, not just thehttp.Handler
- that is,waitGroupHandler
should actually be a {net.Listener
,http.Handler
} pair. The presence of any outstandingAccept
call should blockClose
from returning until thewg.Add
call has completed (e.g. by locking async.Mutex
before callingAccept
on the wrapped listener and locking that same mutex before returning fromClose
). It will take some care to avoid introducing deadlocks or further races.(*waitGroupHandler).ServeHTTP
can't do the synchronization itself:httptest
guarantees that "Close shuts down the server and blocks until all outstanding requests on this server have completed", and allowing a ServeHTTP call to proceed afterClose
(even to write an arbitrary "already closed" error) would violate that guarantee.The text was updated successfully, but these errors were encountered: