http2: support concurrent Request.Close calls

While no guarantees are made about the safety of repeated or
concurrent closes of a request body, HTTP/1 request bodies are
concurrency-safe and HTTP/2 ones should be as well.

Fixes golang/go#51197

Change-Id: Id6527dc2932579cabc9cbe921c6e0b3b4a3d472c
Reviewed-on: https://go-review.googlesource.com/c/net/+/386495
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
diff --git a/http2/server.go b/http2/server.go
index 33765d3..b1c32eb 100644
--- a/http2/server.go
+++ b/http2/server.go
@@ -2316,17 +2316,18 @@
 	_             incomparable
 	stream        *stream
 	conn          *serverConn
-	closed        bool  // for use by Close only
-	sawEOF        bool  // for use by Read only
-	pipe          *pipe // non-nil if we have a HTTP entity message body
-	needsContinue bool  // need to send a 100-continue
+	closeOnce     sync.Once // for use by Close only
+	sawEOF        bool      // for use by Read only
+	pipe          *pipe     // non-nil if we have a HTTP entity message body
+	needsContinue bool      // need to send a 100-continue
 }
 
 func (b *requestBody) Close() error {
-	if b.pipe != nil && !b.closed {
-		b.pipe.BreakWithError(errClosedBody)
-	}
-	b.closed = true
+	b.closeOnce.Do(func() {
+		if b.pipe != nil {
+			b.pipe.BreakWithError(errClosedBody)
+		}
+	})
 	return nil
 }