aboutsummaryrefslogtreecommitdiff
path: root/src/net/http/server.go
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2018-04-12 20:25:07 +0000
committerBrad Fitzpatrick <bradfitz@golang.org>2018-06-15 02:07:23 +0000
commitf70d1e76cc0ed2550d83fbc04356f7d2308044c4 (patch)
treee6f5c1862f6ffa11f17a453ac4bb99063095a3cb /src/net/http/server.go
parent8998c55ec071ae36f2d32c8852a945f032239c4c (diff)
downloadgo-f70d1e76cc0ed2550d83fbc04356f7d2308044c4.tar.xz
net/http: ensure that Listener.Close is called only once in Server.Serve
Fixes #24803 Change-Id: I8b1e7c5a74018a0c333f8c38a7ec5f5827ab1606 Reviewed-on: https://go-review.googlesource.com/106715 Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Diffstat (limited to 'src/net/http/server.go')
-rw-r--r--src/net/http/server.go22
1 files changed, 20 insertions, 2 deletions
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 407546d6c9..d54b745cd2 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -2770,10 +2770,13 @@ var ErrServerClosed = errors.New("http: Server closed")
// Serve always returns a non-nil error. After Shutdown or Close, the
// returned error is ErrServerClosed.
func (srv *Server) Serve(l net.Listener) error {
- defer l.Close()
if fn := testHookServerServe; fn != nil {
- fn(srv, l)
+ fn(srv, l) // call hook with unwrapped listener
}
+
+ l = &onceCloseListener{Listener: l}
+ defer l.Close()
+
var tempDelay time.Duration // how long to sleep on accept failure
if err := srv.setupHTTP2_Serve(); err != nil {
@@ -3249,6 +3252,21 @@ func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
return tc, nil
}
+// onceCloseListener wraps a net.Listener, protecting it from
+// multiple Close calls.
+type onceCloseListener struct {
+ net.Listener
+ once sync.Once
+ closeErr error
+}
+
+func (oc *onceCloseListener) Close() error {
+ oc.once.Do(oc.close)
+ return oc.closeErr
+}
+
+func (oc *onceCloseListener) close() { oc.closeErr = oc.Listener.Close() }
+
// globalOptionsHandler responds to "OPTIONS *" requests.
type globalOptionsHandler struct{}