diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-01-27 17:55:50 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-01-29 11:04:55 -0800 |
commit | 726b7aa004d6885388a76521222602b8552a41ee (patch) | |
tree | 5179037ef840a43dcea0f3be4e07dbcbcfcb2c4a /libgo/go/net | |
parent | 91a95ad2ae0e0f2fa953fafe55ff2ec32c8277d5 (diff) | |
download | gcc-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.go | 3 | ||||
-rw-r--r-- | libgo/go/net/http/fcgi/fcgi_test.go | 12 | ||||
-rw-r--r-- | libgo/go/net/http/httputil/dump.go | 15 | ||||
-rw-r--r-- | libgo/go/net/http/httputil/dump_test.go | 80 | ||||
-rw-r--r-- | libgo/go/net/http/serve_test.go | 6 | ||||
-rw-r--r-- | libgo/go/net/http/server.go | 2 | ||||
-rw-r--r-- | libgo/go/net/http/transport.go | 10 | ||||
-rw-r--r-- | libgo/go/net/http/transport_test.go | 2 | ||||
-rw-r--r-- | libgo/go/net/mail/message_test.go | 8 |
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, }, } |