aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-01-27 17:55:50 -0800
committerIan Lance Taylor <iant@golang.org>2021-01-29 11:04:55 -0800
commit726b7aa004d6885388a76521222602b8552a41ee (patch)
tree5179037ef840a43dcea0f3be4e07dbcbcfcb2c4a /libgo/go/net
parent91a95ad2ae0e0f2fa953fafe55ff2ec32c8277d5 (diff)
downloadgcc-726b7aa004d6885388a76521222602b8552a41ee.zip
gcc-726b7aa004d6885388a76521222602b8552a41ee.tar.gz
gcc-726b7aa004d6885388a76521222602b8552a41ee.tar.bz2
libgo: update to Go1.16rc1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/287493
Diffstat (limited to 'libgo/go/net')
-rw-r--r--libgo/go/net/http/fcgi/child.go3
-rw-r--r--libgo/go/net/http/fcgi/fcgi_test.go12
-rw-r--r--libgo/go/net/http/httputil/dump.go15
-rw-r--r--libgo/go/net/http/httputil/dump_test.go80
-rw-r--r--libgo/go/net/http/serve_test.go6
-rw-r--r--libgo/go/net/http/server.go2
-rw-r--r--libgo/go/net/http/transport.go10
-rw-r--r--libgo/go/net/http/transport_test.go2
-rw-r--r--libgo/go/net/mail/message_test.go8
9 files changed, 110 insertions, 28 deletions
diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go
index e97b844..756722b 100644
--- a/libgo/go/net/http/fcgi/child.go
+++ b/libgo/go/net/http/fcgi/child.go
@@ -171,12 +171,9 @@ func (c *child) serve() {
defer c.cleanUp()
var rec record
for {
- c.conn.mutex.Lock()
if err := rec.read(c.conn.rwc); err != nil {
- c.conn.mutex.Unlock()
return
}
- c.conn.mutex.Unlock()
if err := c.handleRecord(&rec); err != nil {
return
}
diff --git a/libgo/go/net/http/fcgi/fcgi_test.go b/libgo/go/net/http/fcgi/fcgi_test.go
index d3b704f..b58111d 100644
--- a/libgo/go/net/http/fcgi/fcgi_test.go
+++ b/libgo/go/net/http/fcgi/fcgi_test.go
@@ -221,7 +221,11 @@ var cleanUpTests = []struct {
}
type nopWriteCloser struct {
- io.ReadWriter
+ io.Reader
+}
+
+func (nopWriteCloser) Write(buf []byte) (int, error) {
+ return len(buf), nil
}
func (nopWriteCloser) Close() error {
@@ -235,7 +239,7 @@ func TestChildServeCleansUp(t *testing.T) {
for _, tt := range cleanUpTests {
input := make([]byte, len(tt.input))
copy(input, tt.input)
- rc := nopWriteCloser{bytes.NewBuffer(input)}
+ rc := nopWriteCloser{bytes.NewReader(input)}
done := make(chan bool)
c := newChild(rc, http.HandlerFunc(func(
w http.ResponseWriter,
@@ -325,7 +329,7 @@ func TestChildServeReadsEnvVars(t *testing.T) {
for _, tt := range envVarTests {
input := make([]byte, len(tt.input))
copy(input, tt.input)
- rc := nopWriteCloser{bytes.NewBuffer(input)}
+ rc := nopWriteCloser{bytes.NewReader(input)}
done := make(chan bool)
c := newChild(rc, http.HandlerFunc(func(
w http.ResponseWriter,
@@ -375,7 +379,7 @@ func TestResponseWriterSniffsContentType(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
input := make([]byte, len(streamFullRequestStdin))
copy(input, streamFullRequestStdin)
- rc := nopWriteCloser{bytes.NewBuffer(input)}
+ rc := nopWriteCloser{bytes.NewReader(input)}
done := make(chan bool)
var resp *response
c := newChild(rc, http.HandlerFunc(func(
diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go
index 4c9d28b..2948f27 100644
--- a/libgo/go/net/http/httputil/dump.go
+++ b/libgo/go/net/http/httputil/dump.go
@@ -138,6 +138,8 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
select {
case dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n"):
case <-quitReadCh:
+ // Ensure delegateReader.Read doesn't block forever if we get an error.
+ close(dr.c)
}
}()
@@ -146,7 +148,8 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
req.Body = save
if err != nil {
pw.Close()
- quitReadCh <- struct{}{}
+ dr.err = err
+ close(quitReadCh)
return nil, err
}
dump := buf.Bytes()
@@ -167,13 +170,17 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
// delegateReader is a reader that delegates to another reader,
// once it arrives on a channel.
type delegateReader struct {
- c chan io.Reader
- r io.Reader // nil until received from c
+ c chan io.Reader
+ err error // only used if r is nil and c is closed.
+ r io.Reader // nil until received from c
}
func (r *delegateReader) Read(p []byte) (int, error) {
if r.r == nil {
- r.r = <-r.c
+ var ok bool
+ if r.r, ok = <-r.c; !ok {
+ return 0, r.err
+ }
}
return r.r.Read(p)
}
diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go
index 7571eb0..8168b2e 100644
--- a/libgo/go/net/http/httputil/dump_test.go
+++ b/libgo/go/net/http/httputil/dump_test.go
@@ -7,13 +7,17 @@ package httputil
import (
"bufio"
"bytes"
+ "context"
"fmt"
"io"
+ "math/rand"
"net/http"
"net/url"
"runtime"
+ "runtime/pprof"
"strings"
"testing"
+ "time"
)
type eofReader struct{}
@@ -311,11 +315,39 @@ func TestDumpRequest(t *testing.T) {
}
}
}
- if dg := runtime.NumGoroutine() - numg0; dg > 4 {
- buf := make([]byte, 4096)
- buf = buf[:runtime.Stack(buf, true)]
- t.Errorf("Unexpectedly large number of new goroutines: %d new: %s", dg, buf)
+
+ // Validate we haven't leaked any goroutines.
+ var dg int
+ dl := deadline(t, 5*time.Second, time.Second)
+ for time.Now().Before(dl) {
+ if dg = runtime.NumGoroutine() - numg0; dg <= 4 {
+ // No unexpected goroutines.
+ return
+ }
+
+ // Allow goroutines to schedule and die off.
+ runtime.Gosched()
+ }
+
+ buf := make([]byte, 4096)
+ buf = buf[:runtime.Stack(buf, true)]
+ t.Errorf("Unexpectedly large number of new goroutines: %d new: %s", dg, buf)
+}
+
+// deadline returns the time which is needed before t.Deadline()
+// if one is configured and it is s greater than needed in the future,
+// otherwise defaultDelay from the current time.
+func deadline(t *testing.T, defaultDelay, needed time.Duration) time.Time {
+ if dl, ok := t.Deadline(); ok {
+ if dl = dl.Add(-needed); dl.After(time.Now()) {
+ // Allow an arbitrarily long delay.
+ return dl
+ }
}
+
+ // No deadline configured or its closer than needed from now
+ // so just use the default.
+ return time.Now().Add(defaultDelay)
}
func chunk(s string) string {
@@ -445,3 +477,43 @@ func TestDumpResponse(t *testing.T) {
}
}
}
+
+// Issue 38352: Check for deadlock on cancelled requests.
+func TestDumpRequestOutIssue38352(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+ t.Parallel()
+
+ timeout := 10 * time.Second
+ if deadline, ok := t.Deadline(); ok {
+ timeout = time.Until(deadline)
+ timeout -= time.Second * 2 // Leave 2 seconds to report failures.
+ }
+ for i := 0; i < 1000; i++ {
+ delay := time.Duration(rand.Intn(5)) * time.Millisecond
+ ctx, cancel := context.WithTimeout(context.Background(), delay)
+ defer cancel()
+
+ r := bytes.NewBuffer(make([]byte, 10000))
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://example.com", r)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ out := make(chan error)
+ go func() {
+ _, err = DumpRequestOut(req, true)
+ out <- err
+ }()
+
+ select {
+ case <-out:
+ case <-time.After(timeout):
+ b := &bytes.Buffer{}
+ fmt.Fprintf(b, "deadlock detected on iteration %d after %s with delay: %v\n", i, timeout, delay)
+ pprof.Lookup("goroutine").WriteTo(b, 1)
+ t.Fatal(b.String())
+ }
+ }
+}
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index 95e6bf4..f868741 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -6460,13 +6460,15 @@ func TestDisableKeepAliveUpgrade(t *testing.T) {
w.Header().Set("Connection", "Upgrade")
w.Header().Set("Upgrade", "someProto")
w.WriteHeader(StatusSwitchingProtocols)
- c, _, err := w.(Hijacker).Hijack()
+ c, buf, err := w.(Hijacker).Hijack()
if err != nil {
return
}
defer c.Close()
- io.Copy(c, c)
+ // Copy from the *bufio.ReadWriter, which may contain buffered data.
+ // Copy to the net.Conn, to avoid buffering the output.
+ io.Copy(c, buf)
}))
s.Config.SetKeepAlivesEnabled(false)
s.Start()
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index 26c43c2..33aadd6 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -1842,7 +1842,7 @@ func (c *conn) serve(ctx context.Context) {
if d := c.server.WriteTimeout; d != 0 {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}
- if err := tlsConn.HandshakeContext(ctx); err != nil {
+ if err := tlsConn.Handshake(); err != nil {
// If the handshake failed due to the client not speaking
// TLS, assume they're speaking plaintext HTTP and write a
// 400 response on the TLS conn's underlying net.Conn.
diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go
index 6358c38..0aa4827 100644
--- a/libgo/go/net/http/transport.go
+++ b/libgo/go/net/http/transport.go
@@ -1505,7 +1505,7 @@ func (t *Transport) decConnsPerHost(key connectMethodKey) {
// Add TLS to a persistent connection, i.e. negotiate a TLS session. If pconn is already a TLS
// tunnel, this function establishes a nested TLS session inside the encrypted channel.
// The remote endpoint's name may be overridden by TLSClientConfig.ServerName.
-func (pconn *persistConn) addTLS(ctx context.Context, name string, trace *httptrace.ClientTrace) error {
+func (pconn *persistConn) addTLS(name string, trace *httptrace.ClientTrace) error {
// Initiate TLS and check remote host name against certificate.
cfg := cloneTLSConfig(pconn.t.TLSClientConfig)
if cfg.ServerName == "" {
@@ -1527,7 +1527,7 @@ func (pconn *persistConn) addTLS(ctx context.Context, name string, trace *httptr
if trace != nil && trace.TLSHandshakeStart != nil {
trace.TLSHandshakeStart()
}
- err := tlsConn.HandshakeContext(ctx)
+ err := tlsConn.Handshake()
if timer != nil {
timer.Stop()
}
@@ -1583,7 +1583,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
if trace != nil && trace.TLSHandshakeStart != nil {
trace.TLSHandshakeStart()
}
- if err := tc.HandshakeContext(ctx); err != nil {
+ if err := tc.Handshake(); err != nil {
go pconn.conn.Close()
if trace != nil && trace.TLSHandshakeDone != nil {
trace.TLSHandshakeDone(tls.ConnectionState{}, err)
@@ -1607,7 +1607,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
if firstTLSHost, _, err = net.SplitHostPort(cm.addr()); err != nil {
return nil, wrapErr(err)
}
- if err = pconn.addTLS(ctx, firstTLSHost, trace); err != nil {
+ if err = pconn.addTLS(firstTLSHost, trace); err != nil {
return nil, wrapErr(err)
}
}
@@ -1721,7 +1721,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
}
if cm.proxyURL != nil && cm.targetScheme == "https" {
- if err := pconn.addTLS(ctx, cm.tlsHost(), trace); err != nil {
+ if err := pconn.addTLS(cm.tlsHost(), trace); err != nil {
return nil, err
}
}
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index 28fc4ed..cf1f511 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -3738,7 +3738,7 @@ func TestTransportDialTLSContext(t *testing.T) {
if err != nil {
return nil, err
}
- return c, c.HandshakeContext(ctx)
+ return c, c.Handshake()
}
req, err := NewRequest("GET", ts.URL, nil)
diff --git a/libgo/go/net/mail/message_test.go b/libgo/go/net/mail/message_test.go
index 0daa3d6..80a17b2 100644
--- a/libgo/go/net/mail/message_test.go
+++ b/libgo/go/net/mail/message_test.go
@@ -107,8 +107,8 @@ func TestDateParsing(t *testing.T) {
time.Date(1997, 11, 20, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
},
{
- "Thu, 20 Nov 1997 09:55:06 MDT (MDT)",
- time.Date(1997, 11, 20, 9, 55, 6, 0, time.FixedZone("MDT", 0)),
+ "Thu, 20 Nov 1997 09:55:06 GMT (GMT)",
+ time.Date(1997, 11, 20, 9, 55, 6, 0, time.UTC),
},
{
"Fri, 21 Nov 1997 09:55:06 +1300 (TOT)",
@@ -278,8 +278,8 @@ func TestDateParsingCFWS(t *testing.T) {
true,
},
{
- "Fri, 21 Nov 1997 09:55:06 MDT (MDT)",
- time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("MDT", 0)),
+ "Fri, 21 Nov 1997 09:55:06 GMT (GMT)",
+ time.Date(1997, 11, 21, 9, 55, 6, 0, time.UTC),
true,
},
}