diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-09-10 13:14:00 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-09-10 13:14:00 +0000 |
commit | af4b8a523322d6100b52d41ad12d7b602d01331b (patch) | |
tree | 948949901cdcd5af947a3db9a68f59e5c4b415bd /libgo | |
parent | 337fa50b7b0d2964b6ebe2373224b5c1bbb61efb (diff) | |
download | gcc-af4b8a523322d6100b52d41ad12d7b602d01331b.zip gcc-af4b8a523322d6100b52d41ad12d7b602d01331b.tar.gz gcc-af4b8a523322d6100b52d41ad12d7b602d01331b.tar.bz2 |
libgo: update to Go 1.7.1 release
Reviewed-on: https://go-review.googlesource.com/29012
From-SVN: r240071
Diffstat (limited to 'libgo')
28 files changed, 1112 insertions, 255 deletions
diff --git a/libgo/MERGE b/libgo/MERGE index dc6e379..160cfe3 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -8707f31c0abc6b607014e843b7cc188b3019daa9 +f75aafdf56dd90eab75cfeac8cf69358f73ba171 The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/VERSION b/libgo/VERSION index a323ae8..ee106b3 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.7rc3 +go1.7.1 diff --git a/libgo/go/compress/flate/deflate.go b/libgo/go/compress/flate/deflate.go index 8a085ba..9f53d51 100644 --- a/libgo/go/compress/flate/deflate.go +++ b/libgo/go/compress/flate/deflate.go @@ -15,7 +15,17 @@ const ( BestSpeed = 1 BestCompression = 9 DefaultCompression = -1 - HuffmanOnly = -2 // Disables match search and only does Huffman entropy reduction. + + // HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman + // entropy encoding. This mode is useful in compressing data that has + // already been compressed with an LZ style algorithm (e.g. Snappy or LZ4) + // that lacks an entropy encoder. Compression gains are achieved when + // certain bytes in the input stream occur more frequently than others. + // + // Note that HuffmanOnly produces a compressed output that is + // RFC 1951 compliant. That is, any valid DEFLATE decompressor will + // continue to be able to decompress this output. + HuffmanOnly = -2 ) const ( @@ -644,7 +654,6 @@ func (d *compressor) close() error { // a very fast compression for all types of input, but sacrificing considerable // compression efficiency. // -// // If level is in the range [-2, 9] then the error returned will be nil. // Otherwise the error returned will be non-nil. func NewWriter(w io.Writer, level int) (*Writer, error) { @@ -715,7 +724,7 @@ func (w *Writer) Close() error { // the result of NewWriter or NewWriterDict called with dst // and w's level and dictionary. func (w *Writer) Reset(dst io.Writer) { - if dw, ok := w.d.w.w.(*dictWriter); ok { + if dw, ok := w.d.w.writer.(*dictWriter); ok { // w was created with NewWriterDict dw.w = dst w.d.reset(dw) diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go index 27a3b38..3322c40 100644 --- a/libgo/go/compress/flate/deflate_test.go +++ b/libgo/go/compress/flate/deflate_test.go @@ -6,6 +6,7 @@ package flate import ( "bytes" + "errors" "fmt" "internal/testenv" "io" @@ -631,3 +632,52 @@ func TestBestSpeed(t *testing.T) { } } } + +var errIO = errors.New("IO error") + +// failWriter fails with errIO exactly at the nth call to Write. +type failWriter struct{ n int } + +func (w *failWriter) Write(b []byte) (int, error) { + w.n-- + if w.n == -1 { + return 0, errIO + } + return len(b), nil +} + +func TestWriterPersistentError(t *testing.T) { + d, err := ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt") + if err != nil { + t.Fatalf("ReadFile: %v", err) + } + d = d[:10000] // Keep this test short + + zw, err := NewWriter(nil, DefaultCompression) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + + // Sweep over the threshold at which an error is returned. + // The variable i makes it such that the ith call to failWriter.Write will + // return errIO. Since failWriter errors are not persistent, we must ensure + // that flate.Writer errors are persistent. + for i := 0; i < 1000; i++ { + fw := &failWriter{i} + zw.Reset(fw) + + _, werr := zw.Write(d) + cerr := zw.Close() + if werr != errIO && werr != nil { + t.Errorf("test %d, mismatching Write error: got %v, want %v", i, werr, errIO) + } + if cerr != errIO && fw.n < 0 { + t.Errorf("test %d, mismatching Close error: got %v, want %v", i, cerr, errIO) + } + if fw.n >= 0 { + // At this point, the failure threshold was sufficiently high enough + // that we wrote the whole stream without any errors. + return + } + } +} diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go index c4adef9..d8b5a3e 100644 --- a/libgo/go/compress/flate/huffman_bit_writer.go +++ b/libgo/go/compress/flate/huffman_bit_writer.go @@ -77,7 +77,11 @@ var offsetBase = []uint32{ var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} type huffmanBitWriter struct { - w io.Writer + // writer is the underlying writer. + // Do not use it directly; use the write method, which ensures + // that Write errors are sticky. + writer io.Writer + // Data waiting to be written is bytes[0:nbytes] // and then the low nbits of bits. bits uint64 @@ -96,7 +100,7 @@ type huffmanBitWriter struct { func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { return &huffmanBitWriter{ - w: w, + writer: w, literalFreq: make([]int32, maxNumLit), offsetFreq: make([]int32, offsetCodeCount), codegen: make([]uint8, maxNumLit+offsetCodeCount+1), @@ -107,7 +111,7 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { } func (w *huffmanBitWriter) reset(writer io.Writer) { - w.w = writer + w.writer = writer w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil w.bytes = [bufferSize]byte{} } @@ -129,11 +133,21 @@ func (w *huffmanBitWriter) flush() { n++ } w.bits = 0 - _, w.err = w.w.Write(w.bytes[:n]) + w.write(w.bytes[:n]) w.nbytes = 0 } +func (w *huffmanBitWriter) write(b []byte) { + if w.err != nil { + return + } + _, w.err = w.writer.Write(b) +} + func (w *huffmanBitWriter) writeBits(b int32, nb uint) { + if w.err != nil { + return + } w.bits |= uint64(b) << w.nbits w.nbits += nb if w.nbits >= 48 { @@ -150,7 +164,7 @@ func (w *huffmanBitWriter) writeBits(b int32, nb uint) { bytes[5] = byte(bits >> 40) n += 6 if n >= bufferFlushSize { - _, w.err = w.w.Write(w.bytes[:n]) + w.write(w.bytes[:n]) n = 0 } w.nbytes = n @@ -173,13 +187,10 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) { n++ } if n != 0 { - _, w.err = w.w.Write(w.bytes[:n]) - if w.err != nil { - return - } + w.write(w.bytes[:n]) } w.nbytes = 0 - _, w.err = w.w.Write(bytes) + w.write(bytes) } // RFC 1951 3.2.7 specifies a special run-length encoding for specifying @@ -341,7 +352,7 @@ func (w *huffmanBitWriter) writeCode(c hcode) { bytes[5] = byte(bits >> 40) n += 6 if n >= bufferFlushSize { - _, w.err = w.w.Write(w.bytes[:n]) + w.write(w.bytes[:n]) n = 0 } w.nbytes = n @@ -572,6 +583,9 @@ func (w *huffmanBitWriter) indexTokens(tokens []token) (numLiterals, numOffsets // writeTokens writes a slice of tokens to the output. // codes for literal and offset encoding must be supplied. func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) { + if w.err != nil { + return + } for _, t := range tokens { if t < matchType { w.writeCode(leCodes[t.literal()]) @@ -676,9 +690,9 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) { if n < bufferFlushSize { continue } - _, w.err = w.w.Write(w.bytes[:n]) + w.write(w.bytes[:n]) if w.err != nil { - return + return // Return early in the event of write failures } n = 0 } diff --git a/libgo/go/context/context_test.go b/libgo/go/context/context_test.go index 90e78e5..cf18211 100644 --- a/libgo/go/context/context_test.go +++ b/libgo/go/context/context_test.go @@ -255,6 +255,12 @@ func TestDeadline(t *testing.T) { o = otherContext{c} c, _ = WithDeadline(o, time.Now().Add(4*time.Second)) testDeadline(c, "WithDeadline+otherContext+WithDeadline", 2*time.Second, t) + + c, _ = WithDeadline(Background(), time.Now().Add(-time.Millisecond)) + testDeadline(c, "WithDeadline+inthepast", time.Second, t) + + c, _ = WithDeadline(Background(), time.Now()) + testDeadline(c, "WithDeadline+now", time.Second, t) } func TestTimeout(t *testing.T) { diff --git a/libgo/go/crypto/x509/root_cgo_darwin.go b/libgo/go/crypto/x509/root_cgo_darwin.go index 0e2fb35..a4b33c76 100644 --- a/libgo/go/crypto/x509/root_cgo_darwin.go +++ b/libgo/go/crypto/x509/root_cgo_darwin.go @@ -10,9 +10,65 @@ package x509 #cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060 #cgo LDFLAGS: -framework CoreFoundation -framework Security +#include <errno.h> +#include <sys/sysctl.h> + #include <CoreFoundation/CoreFoundation.h> #include <Security/Security.h> +// FetchPEMRoots_MountainLion is the version of FetchPEMRoots from Go 1.6 +// which still works on OS X 10.8 (Mountain Lion). +// It lacks support for admin & user cert domains. +// See golang.org/issue/16473 +int FetchPEMRoots_MountainLion(CFDataRef *pemRoots) { + if (pemRoots == NULL) { + return -1; + } + CFArrayRef certs = NULL; + OSStatus err = SecTrustCopyAnchorCertificates(&certs); + if (err != noErr) { + return -1; + } + CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0); + int i, ncerts = CFArrayGetCount(certs); + for (i = 0; i < ncerts; i++) { + CFDataRef data = NULL; + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i); + if (cert == NULL) { + continue; + } + // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport. + // Once we support weak imports via cgo we should prefer that, and fall back to this + // for older systems. + err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data); + if (err != noErr) { + continue; + } + if (data != NULL) { + CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data)); + CFRelease(data); + } + } + CFRelease(certs); + *pemRoots = combinedData; + return 0; +} + +// useOldCode reports whether the running machine is OS X 10.8 Mountain Lion +// or older. We only support Mountain Lion and higher, but we'll at least try our +// best on older machines and continue to use the old code path. +// +// See golang.org/issue/16473 +int useOldCode() { + char str[256]; + size_t size = sizeof(str); + memset(str, 0, size); + sysctlbyname("kern.osrelease", str, &size, NULL, 0); + // OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*. + // We never supported things before that. + return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0; +} + // FetchPEMRoots fetches the system's list of trusted X.509 root certificates. // // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root @@ -21,6 +77,10 @@ package x509 // Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after // we've consumed its content. int FetchPEMRoots(CFDataRef *pemRoots) { + if (useOldCode()) { + return FetchPEMRoots_MountainLion(pemRoots); + } + // Get certificates from all domains, not just System, this lets // the user add CAs to their "login" keychain, and Admins to add // to the "System" keychain diff --git a/libgo/go/hash/crc32/crc32_s390x.go b/libgo/go/hash/crc32/crc32_s390x.go index b8a5808..2a7926b 100644 --- a/libgo/go/hash/crc32/crc32_s390x.go +++ b/libgo/go/hash/crc32/crc32_s390x.go @@ -6,14 +6,9 @@ package crc32 -import ( - "unsafe" -) - const ( vxMinLen = 64 - vxAlignment = 16 - vxAlignMask = vxAlignment - 1 + vxAlignMask = 15 // align to 16 bytes ) // hasVectorFacility reports whether the machine has the z/Architecture @@ -51,20 +46,13 @@ func genericIEEE(crc uint32, p []byte) uint32 { return update(crc, IEEETable, p) } -// updateCastagnoli calculates the checksum of p using genericCastagnoli to -// align the data appropriately for vectorCastagnoli. It avoids using -// vectorCastagnoli entirely if the length of p is less than or equal to -// vxMinLen. +// updateCastagnoli calculates the checksum of p using +// vectorizedCastagnoli if possible and falling back onto +// genericCastagnoli as needed. func updateCastagnoli(crc uint32, p []byte) uint32 { // Use vectorized function if vector facility is available and // data length is above threshold. - if hasVX && len(p) > vxMinLen { - pAddr := uintptr(unsafe.Pointer(&p[0])) - if pAddr&vxAlignMask != 0 { - prealign := vxAlignment - int(pAddr&vxAlignMask) - crc = genericCastagnoli(crc, p[:prealign]) - p = p[prealign:] - } + if hasVX && len(p) >= vxMinLen { aligned := len(p) & ^vxAlignMask crc = vectorizedCastagnoli(crc, p[:aligned]) p = p[aligned:] @@ -77,19 +65,12 @@ func updateCastagnoli(crc uint32, p []byte) uint32 { return genericCastagnoli(crc, p) } -// updateIEEE calculates the checksum of p using genericIEEE to align the data -// appropriately for vectorIEEE. It avoids using vectorIEEE entirely if the length -// of p is less than or equal to vxMinLen. +// updateIEEE calculates the checksum of p using vectorizedIEEE if +// possible and falling back onto genericIEEE as needed. func updateIEEE(crc uint32, p []byte) uint32 { // Use vectorized function if vector facility is available and // data length is above threshold. - if hasVX && len(p) > vxMinLen { - pAddr := uintptr(unsafe.Pointer(&p[0])) - if pAddr&vxAlignMask != 0 { - prealign := vxAlignment - int(pAddr&vxAlignMask) - crc = genericIEEE(crc, p[:prealign]) - p = p[prealign:] - } + if hasVX && len(p) >= vxMinLen { aligned := len(p) & ^vxAlignMask crc = vectorizedIEEE(crc, p[:aligned]) p = p[aligned:] diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go index ed05cac..3a9d036 100644 --- a/libgo/go/io/multi.go +++ b/libgo/go/io/multi.go @@ -18,15 +18,16 @@ func (mr *multiReader) Read(p []byte) (n int, err error) { } } n, err = mr.readers[0].Read(p) + if err == EOF { + mr.readers = mr.readers[1:] + } if n > 0 || err != EOF { - if err == EOF { - // Don't return EOF yet. There may be more bytes - // in the remaining readers. + if err == EOF && len(mr.readers) > 0 { + // Don't return EOF yet. More readers remain. err = nil } return } - mr.readers = mr.readers[1:] } return 0, EOF } diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go index a434453..447e7f5 100644 --- a/libgo/go/io/multi_test.go +++ b/libgo/go/io/multi_test.go @@ -197,3 +197,41 @@ func TestMultiReaderFlatten(t *testing.T) { myDepth+2, readDepth) } } + +// byteAndEOFReader is a Reader which reads one byte (the underlying +// byte) and io.EOF at once in its Read call. +type byteAndEOFReader byte + +func (b byteAndEOFReader) Read(p []byte) (n int, err error) { + if len(p) == 0 { + // Read(0 bytes) is useless. We expect no such useless + // calls in this test. + panic("unexpected call") + } + p[0] = byte(b) + return 1, EOF +} + +// In Go 1.7, this yielded bytes forever. +func TestMultiReaderSingleByteWithEOF(t *testing.T) { + got, err := ioutil.ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10)) + if err != nil { + t.Fatal(err) + } + const want = "ab" + if string(got) != want { + t.Errorf("got %q; want %q", got, want) + } +} + +// Test that a reader returning (n, EOF) at the end of an MultiReader +// chain continues to return EOF on its final read, rather than +// yielding a (0, EOF). +func TestMultiReaderFinalEOF(t *testing.T) { + r := MultiReader(bytes.NewReader(nil), byteAndEOFReader('a')) + buf := make([]byte, 2) + n, err := r.Read(buf) + if n != 1 || err != EOF { + t.Errorf("got %v, %v; want 1, EOF", n, err) + } +} diff --git a/libgo/go/net/dial_unix_test.go b/libgo/go/net/dial_unix_test.go new file mode 100644 index 0000000..4705254 --- /dev/null +++ b/libgo/go/net/dial_unix_test.go @@ -0,0 +1,108 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package net + +import ( + "context" + "syscall" + "testing" + "time" +) + +// Issue 16523 +func TestDialContextCancelRace(t *testing.T) { + oldConnectFunc := connectFunc + oldGetsockoptIntFunc := getsockoptIntFunc + oldTestHookCanceledDial := testHookCanceledDial + defer func() { + connectFunc = oldConnectFunc + getsockoptIntFunc = oldGetsockoptIntFunc + testHookCanceledDial = oldTestHookCanceledDial + }() + + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + listenerDone := make(chan struct{}) + go func() { + defer close(listenerDone) + c, err := ln.Accept() + if err == nil { + c.Close() + } + }() + defer func() { <-listenerDone }() + defer ln.Close() + + sawCancel := make(chan bool, 1) + testHookCanceledDial = func() { + sawCancel <- true + } + + ctx, cancelCtx := context.WithCancel(context.Background()) + + connectFunc = func(fd int, addr syscall.Sockaddr) error { + err := oldConnectFunc(fd, addr) + t.Logf("connect(%d, addr) = %v", fd, err) + if err == nil { + // On some operating systems, localhost + // connects _sometimes_ succeed immediately. + // Prevent that, so we exercise the code path + // we're interested in testing. This seems + // harmless. It makes FreeBSD 10.10 work when + // run with many iterations. It failed about + // half the time previously. + return syscall.EINPROGRESS + } + return err + } + + getsockoptIntFunc = func(fd, level, opt int) (val int, err error) { + val, err = oldGetsockoptIntFunc(fd, level, opt) + t.Logf("getsockoptIntFunc(%d, %d, %d) = (%v, %v)", fd, level, opt, val, err) + if level == syscall.SOL_SOCKET && opt == syscall.SO_ERROR && err == nil && val == 0 { + t.Logf("canceling context") + + // Cancel the context at just the moment which + // caused the race in issue 16523. + cancelCtx() + + // And wait for the "interrupter" goroutine to + // cancel the dial by messing with its write + // timeout before returning. + select { + case <-sawCancel: + t.Logf("saw cancel") + case <-time.After(5 * time.Second): + t.Errorf("didn't see cancel after 5 seconds") + } + } + return + } + + var d Dialer + c, err := d.DialContext(ctx, "tcp", ln.Addr().String()) + if err == nil { + c.Close() + t.Fatal("unexpected successful dial; want context canceled error") + } + + select { + case <-ctx.Done(): + case <-time.After(5 * time.Second): + t.Fatal("expected context to be canceled") + } + + oe, ok := err.(*OpError) + if !ok || oe.Op != "dial" { + t.Fatalf("Dial error = %#v; want dial *OpError", err) + } + if oe.Err != ctx.Err() { + t.Errorf("DialContext = (%v, %v); want OpError with error %v", c, err, ctx.Err()) + } +} diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index 8f2dff4..b5b6ffb 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -141,7 +141,7 @@ func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn, } // exchange sends a query on the connection and hopes for a response. -func exchange(ctx context.Context, server, name string, qtype uint16) (*dnsMsg, error) { +func exchange(ctx context.Context, server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) { d := testHookDNSDialer() out := dnsMsg{ dnsMsgHdr: dnsMsgHdr{ @@ -152,6 +152,12 @@ func exchange(ctx context.Context, server, name string, qtype uint16) (*dnsMsg, }, } for _, network := range []string{"udp", "tcp"} { + // TODO(mdempsky): Refactor so defers from UDP-based + // exchanges happen before TCP-based exchange. + + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) + defer cancel() + c, err := d.dialDNS(ctx, network, server) if err != nil { return nil, err @@ -180,17 +186,10 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) return "", nil, &DNSError{Err: "no DNS servers", Name: name} } - deadline := time.Now().Add(cfg.timeout) - if old, ok := ctx.Deadline(); !ok || deadline.Before(old) { - var cancel context.CancelFunc - ctx, cancel = context.WithDeadline(ctx, deadline) - defer cancel() - } - var lastErr error for i := 0; i < cfg.attempts; i++ { for _, server := range cfg.servers { - msg, err := exchange(ctx, server, name, qtype) + msg, err := exchange(ctx, server, name, qtype, cfg.timeout) if err != nil { lastErr = &DNSError{ Err: err.Error(), @@ -338,8 +337,9 @@ func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs [ } // avoidDNS reports whether this is a hostname for which we should not -// use DNS. Currently this includes only .onion and .local names, -// per RFC 7686 and RFC 6762, respectively. See golang.org/issue/13705. +// use DNS. Currently this includes only .onion, per RFC 7686. See +// golang.org/issue/13705. Does not cover .local names (RFC 6762), +// see golang.org/issue/16739. func avoidDNS(name string) bool { if name == "" { return true @@ -347,7 +347,7 @@ func avoidDNS(name string) bool { if name[len(name)-1] == '.' { name = name[:len(name)-1] } - return stringsHasSuffixFold(name, ".onion") || stringsHasSuffixFold(name, ".local") + return stringsHasSuffixFold(name, ".onion") } // nameList returns a list of names for sequential DNS queries. diff --git a/libgo/go/net/dnsclient_unix_test.go b/libgo/go/net/dnsclient_unix_test.go index 09bbd48..6ebeeae 100644 --- a/libgo/go/net/dnsclient_unix_test.go +++ b/libgo/go/net/dnsclient_unix_test.go @@ -40,9 +40,9 @@ func TestDNSTransportFallback(t *testing.T) { testenv.MustHaveExternalNetwork(t) for _, tt := range dnsTransportFallbackTests { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(tt.timeout)*time.Second) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() - msg, err := exchange(ctx, tt.server, tt.name, tt.qtype) + msg, err := exchange(ctx, tt.server, tt.name, tt.qtype, time.Second) if err != nil { t.Error(err) continue @@ -82,9 +82,9 @@ func TestSpecialDomainName(t *testing.T) { server := "8.8.8.8:53" for _, tt := range specialDomainNameTests { - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() - msg, err := exchange(ctx, server, tt.name, tt.qtype) + msg, err := exchange(ctx, server, tt.name, tt.qtype, 3*time.Second) if err != nil { t.Error(err) continue @@ -112,10 +112,11 @@ func TestAvoidDNSName(t *testing.T) { {"foo.ONION", true}, {"foo.ONION.", true}, - {"foo.local.", true}, - {"foo.local", true}, - {"foo.LOCAL", true}, - {"foo.LOCAL.", true}, + // But do resolve *.local address; Issue 16739 + {"foo.local.", false}, + {"foo.local", false}, + {"foo.LOCAL", false}, + {"foo.LOCAL.", false}, {"", true}, // will be rejected earlier too @@ -500,7 +501,7 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) { d := &fakeDNSDialer{} testHookDNSDialer = func() dnsDialer { return d } - d.rh = func(s string, q *dnsMsg) (*dnsMsg, error) { + d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) { r := &dnsMsg{ dnsMsgHdr: dnsMsgHdr{ id: q.id, @@ -539,14 +540,15 @@ func TestIgnoreLameReferrals(t *testing.T) { } defer conf.teardown() - if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", "nameserver 192.0.2.2"}); err != nil { + if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will give a lame referral + "nameserver 192.0.2.2"}); err != nil { t.Fatal(err) } d := &fakeDNSDialer{} testHookDNSDialer = func() dnsDialer { return d } - d.rh = func(s string, q *dnsMsg) (*dnsMsg, error) { + d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) { t.Log(s, q) r := &dnsMsg{ dnsMsgHdr: dnsMsgHdr{ @@ -633,28 +635,30 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) { type fakeDNSDialer struct { // reply handler - rh func(s string, q *dnsMsg) (*dnsMsg, error) + rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error) } func (f *fakeDNSDialer) dialDNS(_ context.Context, n, s string) (dnsConn, error) { - return &fakeDNSConn{f.rh, s}, nil + return &fakeDNSConn{f.rh, s, time.Time{}}, nil } type fakeDNSConn struct { - rh func(s string, q *dnsMsg) (*dnsMsg, error) + rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error) s string + t time.Time } func (f *fakeDNSConn) Close() error { return nil } -func (f *fakeDNSConn) SetDeadline(time.Time) error { +func (f *fakeDNSConn) SetDeadline(t time.Time) error { + f.t = t return nil } func (f *fakeDNSConn) dnsRoundTrip(q *dnsMsg) (*dnsMsg, error) { - return f.rh(f.s, q) + return f.rh(f.s, q, f.t) } // UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281). @@ -724,3 +728,72 @@ func TestIgnoreDNSForgeries(t *testing.T) { t.Errorf("got address %v, want %v", got, TestAddr) } } + +// Issue 16865. If a name server times out, continue to the next. +func TestRetryTimeout(t *testing.T) { + origTestHookDNSDialer := testHookDNSDialer + defer func() { testHookDNSDialer = origTestHookDNSDialer }() + + conf, err := newResolvConfTest() + if err != nil { + t.Fatal(err) + } + defer conf.teardown() + + if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will timeout + "nameserver 192.0.2.2"}); err != nil { + t.Fatal(err) + } + + d := &fakeDNSDialer{} + testHookDNSDialer = func() dnsDialer { return d } + + var deadline0 time.Time + + d.rh = func(s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) { + t.Log(s, q, deadline) + + if deadline.IsZero() { + t.Error("zero deadline") + } + + if s == "192.0.2.1:53" { + deadline0 = deadline + time.Sleep(10 * time.Millisecond) + return nil, errTimeout + } + + if deadline == deadline0 { + t.Error("deadline didn't change") + } + + r := &dnsMsg{ + dnsMsgHdr: dnsMsgHdr{ + id: q.id, + response: true, + recursion_available: true, + }, + question: q.question, + answer: []dnsRR{ + &dnsRR_CNAME{ + Hdr: dnsRR_Header{ + Name: q.question[0].Name, + Rrtype: dnsTypeCNAME, + Class: dnsClassINET, + }, + Cname: "golang.org", + }, + }, + } + return r, nil + } + + _, err = goLookupCNAME(context.Background(), "www.golang.org") + if err != nil { + t.Fatal(err) + } + + if deadline0.IsZero() { + t.Error("deadline0 still zero", deadline0) + } +} diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go index 6fbb9cb..0309db0 100644 --- a/libgo/go/net/fd_unix.go +++ b/libgo/go/net/fd_unix.go @@ -64,7 +64,7 @@ func (fd *netFD) name() string { return fd.net + ":" + ls + "->" + rs } -func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error { +func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (ret error) { // Do not need to call fd.writeLock here, // because fd is not yet accessible to user, // so no concurrent operations are possible. @@ -101,21 +101,44 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error { defer fd.setWriteDeadline(noDeadline) } - // Wait for the goroutine converting context.Done into a write timeout - // to exist, otherwise our caller might cancel the context and - // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial. - done := make(chan bool) // must be unbuffered - defer func() { done <- true }() - go func() { - select { - case <-ctx.Done(): - // Force the runtime's poller to immediately give - // up waiting for writability. - fd.setWriteDeadline(aLongTimeAgo) - <-done - case <-done: - } - }() + // Start the "interrupter" goroutine, if this context might be canceled. + // (The background context cannot) + // + // The interrupter goroutine waits for the context to be done and + // interrupts the dial (by altering the fd's write deadline, which + // wakes up waitWrite). + if ctx != context.Background() { + // Wait for the interrupter goroutine to exit before returning + // from connect. + done := make(chan struct{}) + interruptRes := make(chan error) + defer func() { + close(done) + if ctxErr := <-interruptRes; ctxErr != nil && ret == nil { + // The interrupter goroutine called setWriteDeadline, + // but the connect code below had returned from + // waitWrite already and did a successful connect (ret + // == nil). Because we've now poisoned the connection + // by making it unwritable, don't return a successful + // dial. This was issue 16523. + ret = ctxErr + fd.Close() // prevent a leak + } + }() + go func() { + select { + case <-ctx.Done(): + // Force the runtime's poller to immediately give up + // waiting for writability, unblocking waitWrite + // below. + fd.setWriteDeadline(aLongTimeAgo) + testHookCanceledDial() + interruptRes <- ctx.Err() + case <-done: + interruptRes <- nil + } + }() + } for { // Performing multiple connect system calls on a diff --git a/libgo/go/net/hook_unix.go b/libgo/go/net/hook_unix.go index 361ca59..cf52567 100644 --- a/libgo/go/net/hook_unix.go +++ b/libgo/go/net/hook_unix.go @@ -9,7 +9,8 @@ package net import "syscall" var ( - testHookDialChannel = func() {} // see golang.org/issue/5349 + testHookDialChannel = func() {} // for golang.org/issue/5349 + testHookCanceledDial = func() {} // for golang.org/issue/16523 // Placeholders for socket system calls. socketFunc func(int, int, int) (int, error) = syscall.Socket diff --git a/libgo/go/net/http/h2_bundle.go b/libgo/go/net/http/h2_bundle.go index db77455..5826bb7 100644 --- a/libgo/go/net/http/h2_bundle.go +++ b/libgo/go/net/http/h2_bundle.go @@ -28,6 +28,7 @@ import ( "io" "io/ioutil" "log" + "math" "net" "net/http/httptrace" "net/textproto" @@ -85,7 +86,16 @@ const ( http2noDialOnMiss = false ) -func (p *http2clientConnPool) getClientConn(_ *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) { +func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMiss bool) (*http2ClientConn, error) { + if http2isConnectionCloseRequest(req) && dialOnMiss { + // It gets its own connection. + const singleUse = true + cc, err := p.t.dialClientConn(addr, singleUse) + if err != nil { + return nil, err + } + return cc, nil + } p.mu.Lock() for _, cc := range p.conns[addr] { if cc.CanTakeNewRequest() { @@ -128,7 +138,8 @@ func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall { // run in its own goroutine. func (c *http2dialCall) dial(addr string) { - c.res, c.err = c.p.t.dialClientConn(addr) + const singleUse = false // shared conn + c.res, c.err = c.p.t.dialClientConn(addr, singleUse) close(c.done) c.p.mu.Lock() @@ -393,9 +404,17 @@ func (e http2ConnectionError) Error() string { type http2StreamError struct { StreamID uint32 Code http2ErrCode + Cause error // optional additional detail +} + +func http2streamError(id uint32, code http2ErrCode) http2StreamError { + return http2StreamError{StreamID: id, Code: code} } func (e http2StreamError) Error() string { + if e.Cause != nil { + return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause) + } return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code) } @@ -1105,6 +1124,7 @@ func http2parseDataFrame(fh http2FrameHeader, payload []byte) (http2Frame, error var ( http2errStreamID = errors.New("invalid stream ID") http2errDepStreamID = errors.New("invalid dependent stream ID") + http2errPadLength = errors.New("pad length too large") ) func http2validStreamIDOrZero(streamID uint32) bool { @@ -1118,18 +1138,40 @@ func http2validStreamID(streamID uint32) bool { // WriteData writes a DATA frame. // // It will perform exactly one Write to the underlying Writer. -// It is the caller's responsibility to not call other Write methods concurrently. +// It is the caller's responsibility not to violate the maximum frame size +// and to not call other Write methods concurrently. func (f *http2Framer) WriteData(streamID uint32, endStream bool, data []byte) error { + return f.WriteDataPadded(streamID, endStream, data, nil) +} +// WriteData writes a DATA frame with optional padding. +// +// If pad is nil, the padding bit is not sent. +// The length of pad must not exceed 255 bytes. +// +// It will perform exactly one Write to the underlying Writer. +// It is the caller's responsibility not to violate the maximum frame size +// and to not call other Write methods concurrently. +func (f *http2Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []byte) error { if !http2validStreamID(streamID) && !f.AllowIllegalWrites { return http2errStreamID } + if len(pad) > 255 { + return http2errPadLength + } var flags http2Flags if endStream { flags |= http2FlagDataEndStream } + if pad != nil { + flags |= http2FlagDataPadded + } f.startWrite(http2FrameData, flags, streamID) + if pad != nil { + f.wbuf = append(f.wbuf, byte(len(pad))) + } f.wbuf = append(f.wbuf, data...) + f.wbuf = append(f.wbuf, pad...) return f.endWrite() } @@ -1333,7 +1375,7 @@ func http2parseWindowUpdateFrame(fh http2FrameHeader, p []byte) (http2Frame, err if fh.StreamID == 0 { return nil, http2ConnectionError(http2ErrCodeProtocol) } - return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol} + return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol) } return &http2WindowUpdateFrame{ http2FrameHeader: fh, @@ -1411,7 +1453,7 @@ func http2parseHeadersFrame(fh http2FrameHeader, p []byte) (_ http2Frame, err er } } if len(p)-int(padLength) <= 0 { - return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol} + return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol) } hf.headerFragBuf = p[:len(p)-int(padLength)] return hf, nil @@ -1878,6 +1920,9 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr hdec.SetEmitEnabled(true) hdec.SetMaxStringLength(fr.maxHeaderStringLen()) hdec.SetEmitFunc(func(hf hpack.HeaderField) { + if http2VerboseLogs && http2logFrameReads { + log.Printf("http2: decoded hpack field %+v", hf) + } if !httplex.ValidHeaderFieldValue(hf.Value) { invalid = http2headerFieldValueError(hf.Value) } @@ -1936,11 +1981,17 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr } if invalid != nil { fr.errDetail = invalid - return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol} + if http2VerboseLogs { + log.Printf("http2: invalid header: %v", invalid) + } + return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, invalid} } if err := mh.checkPseudos(); err != nil { fr.errDetail = err - return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol} + if http2VerboseLogs { + log.Printf("http2: invalid pseudo headers: %v", err) + } + return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, err} } return mh, nil } @@ -3571,7 +3622,7 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) { case http2stateOpen: st.state = http2stateHalfClosedLocal - errCancel := http2StreamError{st.id, http2ErrCodeCancel} + errCancel := http2streamError(st.id, http2ErrCodeCancel) sc.resetStream(errCancel) case http2stateHalfClosedRemote: sc.closeStream(st, http2errHandlerComplete) @@ -3764,7 +3815,7 @@ func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error return nil } if !st.flow.add(int32(f.Increment)) { - return http2StreamError{f.StreamID, http2ErrCodeFlowControl} + return http2streamError(f.StreamID, http2ErrCodeFlowControl) } default: if !sc.flow.add(int32(f.Increment)) { @@ -3786,7 +3837,7 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error { if st != nil { st.gotReset = true st.cancelCtx() - sc.closeStream(st, http2StreamError{f.StreamID, f.ErrCode}) + sc.closeStream(st, http2streamError(f.StreamID, f.ErrCode)) } return nil } @@ -3803,6 +3854,9 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) { } delete(sc.streams, st.id) if p := st.body; p != nil { + + sc.sendWindowUpdate(nil, p.Len()) + p.CloseWithError(err) } st.cw.Close() @@ -3879,36 +3933,51 @@ func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error { func (sc *http2serverConn) processData(f *http2DataFrame) error { sc.serveG.check() + data := f.Data() id := f.Header().StreamID st, ok := sc.streams[id] if !ok || st.state != http2stateOpen || st.gotTrailerHeader { - return http2StreamError{id, http2ErrCodeStreamClosed} + if sc.inflow.available() < int32(f.Length) { + return http2streamError(id, http2ErrCodeFlowControl) + } + + sc.inflow.take(int32(f.Length)) + sc.sendWindowUpdate(nil, int(f.Length)) + + return http2streamError(id, http2ErrCodeStreamClosed) } if st.body == nil { panic("internal error: should have a body in this state") } - data := f.Data() if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes { st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes)) - return http2StreamError{id, http2ErrCodeStreamClosed} + return http2streamError(id, http2ErrCodeStreamClosed) } - if len(data) > 0 { + if f.Length > 0 { - if int(st.inflow.available()) < len(data) { - return http2StreamError{id, http2ErrCodeFlowControl} + if st.inflow.available() < int32(f.Length) { + return http2streamError(id, http2ErrCodeFlowControl) } - st.inflow.take(int32(len(data))) - wrote, err := st.body.Write(data) - if err != nil { - return http2StreamError{id, http2ErrCodeStreamClosed} + st.inflow.take(int32(f.Length)) + + if len(data) > 0 { + wrote, err := st.body.Write(data) + if err != nil { + return http2streamError(id, http2ErrCodeStreamClosed) + } + if wrote != len(data) { + panic("internal error: bad Writer") + } + st.bodyBytes += int64(len(data)) } - if wrote != len(data) { - panic("internal error: bad Writer") + + if pad := int32(f.Length) - int32(len(data)); pad > 0 { + sc.sendWindowUpdate32(nil, pad) + sc.sendWindowUpdate32(st, pad) } - st.bodyBytes += int64(len(data)) } if f.StreamEnded() { st.endStream() @@ -3995,10 +4064,10 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error { if sc.unackedSettings == 0 { - return http2StreamError{st.id, http2ErrCodeProtocol} + return http2streamError(st.id, http2ErrCodeProtocol) } - return http2StreamError{st.id, http2ErrCodeRefusedStream} + return http2streamError(st.id, http2ErrCodeRefusedStream) } rw, req, err := sc.newWriterAndRequest(st, f) @@ -4032,18 +4101,18 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error { } st.gotTrailerHeader = true if !f.StreamEnded() { - return http2StreamError{st.id, http2ErrCodeProtocol} + return http2streamError(st.id, http2ErrCodeProtocol) } if len(f.PseudoFields()) > 0 { - return http2StreamError{st.id, http2ErrCodeProtocol} + return http2streamError(st.id, http2ErrCodeProtocol) } if st.trailer != nil { for _, hf := range f.RegularFields() { key := sc.canonicalHeader(hf.Name) if !http2ValidTrailerHeader(key) { - return http2StreamError{st.id, http2ErrCodeProtocol} + return http2streamError(st.id, http2ErrCodeProtocol) } st.trailer[key] = append(st.trailer[key], hf.Value) } @@ -4097,18 +4166,18 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead isConnect := method == "CONNECT" if isConnect { if path != "" || scheme != "" || authority == "" { - return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol} + return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol) } } else if method == "" || path == "" || (scheme != "https" && scheme != "http") { - return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol} + return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol) } bodyOpen := !f.StreamEnded() if method == "HEAD" && bodyOpen { - return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol} + return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol) } var tlsState *tls.ConnectionState // nil if not scheme https @@ -4165,7 +4234,7 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead var err error url_, err = url.ParseRequestURI(path) if err != nil { - return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol} + return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol) } requestURI = path } @@ -4919,35 +4988,37 @@ func (t *http2Transport) initConnPool() { // ClientConn is the state of a single HTTP/2 client connection to an // HTTP/2 server. type http2ClientConn struct { - t *http2Transport - tconn net.Conn // usually *tls.Conn, except specialized impls - tlsState *tls.ConnectionState // nil only for specialized impls + t *http2Transport + tconn net.Conn // usually *tls.Conn, except specialized impls + tlsState *tls.ConnectionState // nil only for specialized impls + singleUse bool // whether being used for a single http.Request // readLoop goroutine fields: readerDone chan struct{} // closed on error readerErr error // set before readerDone is closed - mu sync.Mutex // guards following - cond *sync.Cond // hold mu; broadcast on flow/closed changes - flow http2flow // our conn-level flow control quota (cs.flow is per stream) - inflow http2flow // peer's conn-level flow control - closed bool - goAway *http2GoAwayFrame // if non-nil, the GoAwayFrame we received - goAwayDebug string // goAway frame's debug data, retained as a string - streams map[uint32]*http2clientStream // client-initiated - nextStreamID uint32 - bw *bufio.Writer - br *bufio.Reader - fr *http2Framer - lastActive time.Time - - // Settings from peer: + mu sync.Mutex // guards following + cond *sync.Cond // hold mu; broadcast on flow/closed changes + flow http2flow // our conn-level flow control quota (cs.flow is per stream) + inflow http2flow // peer's conn-level flow control + closed bool + wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back + goAway *http2GoAwayFrame // if non-nil, the GoAwayFrame we received + goAwayDebug string // goAway frame's debug data, retained as a string + streams map[uint32]*http2clientStream // client-initiated + nextStreamID uint32 + bw *bufio.Writer + br *bufio.Reader + fr *http2Framer + lastActive time.Time + // Settings from peer: (also guarded by mu) maxFrameSize uint32 maxConcurrentStreams uint32 initialWindowSize uint32 - hbuf bytes.Buffer // HPACK encoder writes into this - henc *hpack.Encoder - freeBuf [][]byte + + hbuf bytes.Buffer // HPACK encoder writes into this + henc *hpack.Encoder + freeBuf [][]byte wmu sync.Mutex // held while writing; acquire AFTER mu if holding both werr error // first write error that has occurred @@ -5117,7 +5188,7 @@ func http2shouldRetryRequest(req *Request, err error) bool { return err == http2errClientConnUnusable } -func (t *http2Transport) dialClientConn(addr string) (*http2ClientConn, error) { +func (t *http2Transport) dialClientConn(addr string, singleUse bool) (*http2ClientConn, error) { host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err @@ -5126,7 +5197,7 @@ func (t *http2Transport) dialClientConn(addr string) (*http2ClientConn, error) { if err != nil { return nil, err } - return t.NewClientConn(tconn) + return t.newClientConn(tconn, singleUse) } func (t *http2Transport) newTLSConfig(host string) *tls.Config { @@ -5187,14 +5258,10 @@ func (t *http2Transport) expectContinueTimeout() time.Duration { } func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { - if http2VerboseLogs { - t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr()) - } - if _, err := c.Write(http2clientPreface); err != nil { - t.vlogf("client preface write error: %v", err) - return nil, err - } + return t.newClientConn(c, false) +} +func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2ClientConn, error) { cc := &http2ClientConn{ t: t, tconn: c, @@ -5204,7 +5271,13 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { initialWindowSize: 65535, maxConcurrentStreams: 1000, streams: make(map[uint32]*http2clientStream), + singleUse: singleUse, + wantSettingsAck: true, } + if http2VerboseLogs { + t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr()) + } + cc.cond = sync.NewCond(&cc.mu) cc.flow.add(int32(http2initialWindowSize)) @@ -5228,6 +5301,8 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { if max := t.maxHeaderListSize(); max != 0 { initialSettings = append(initialSettings, http2Setting{ID: http2SettingMaxHeaderListSize, Val: max}) } + + cc.bw.Write(http2clientPreface) cc.fr.WriteSettings(initialSettings...) cc.fr.WriteWindowUpdate(0, http2transportDefaultConnFlow) cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize) @@ -5236,32 +5311,6 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { return nil, cc.werr } - f, err := cc.fr.ReadFrame() - if err != nil { - return nil, err - } - sf, ok := f.(*http2SettingsFrame) - if !ok { - return nil, fmt.Errorf("expected settings frame, got: %T", f) - } - cc.fr.WriteSettingsAck() - cc.bw.Flush() - - sf.ForeachSetting(func(s http2Setting) error { - switch s.ID { - case http2SettingMaxFrameSize: - cc.maxFrameSize = s.Val - case http2SettingMaxConcurrentStreams: - cc.maxConcurrentStreams = s.Val - case http2SettingInitialWindowSize: - cc.initialWindowSize = s.Val - default: - - t.vlogf("Unhandled Setting: %v", s) - } - return nil - }) - go cc.readLoop() return cc, nil } @@ -5288,9 +5337,12 @@ func (cc *http2ClientConn) CanTakeNewRequest() bool { } func (cc *http2ClientConn) canTakeNewRequestLocked() bool { + if cc.singleUse && cc.nextStreamID > 1 { + return false + } return cc.goAway == nil && !cc.closed && int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) && - cc.nextStreamID < 2147483647 + cc.nextStreamID < math.MaxInt32 } func (cc *http2ClientConn) closeIfIdle() { @@ -5300,9 +5352,13 @@ func (cc *http2ClientConn) closeIfIdle() { return } cc.closed = true + nextID := cc.nextStreamID cc.mu.Unlock() + if http2VerboseLogs { + cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2) + } cc.tconn.Close() } @@ -5404,12 +5460,15 @@ func http2bodyAndLength(req *Request) (body io.Reader, contentLen int64) { // We have a body but a zero content length. Test to see if // it's actually zero or just unset. var buf [1]byte - n, rerr := io.ReadFull(body, buf[:]) + n, rerr := body.Read(buf[:]) if rerr != nil && rerr != io.EOF { return http2errorReader{rerr}, -1 } if n == 1 { + if rerr == io.EOF { + return bytes.NewReader(buf[:]), 1 + } return io.MultiReader(bytes.NewReader(buf[:]), body), -1 } @@ -5494,9 +5553,10 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { bodyWritten := false ctx := http2reqContext(req) - reFunc := func(re http2resAndError) (*Response, error) { + handleReadLoopResponse := func(re http2resAndError) (*Response, error) { res := re.res if re.err != nil || res.StatusCode > 299 { + bodyWriter.cancel() cs.abortRequestBodyWrite(http2errStopReqBodyWrite) } @@ -5512,7 +5572,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { for { select { case re := <-readLoopResCh: - return reFunc(re) + return handleReadLoopResponse(re) case <-respHeaderTimer: cc.forgetStreamID(cs.ID) if !hasBody || bodyWritten { @@ -5525,7 +5585,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { case <-ctx.Done(): select { case re := <-readLoopResCh: - return reFunc(re) + return handleReadLoopResponse(re) default: } cc.forgetStreamID(cs.ID) @@ -5539,7 +5599,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { case <-req.Cancel: select { case re := <-readLoopResCh: - return reFunc(re) + return handleReadLoopResponse(re) default: } cc.forgetStreamID(cs.ID) @@ -5553,14 +5613,15 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { case <-cs.peerReset: select { case re := <-readLoopResCh: - return reFunc(re) + return handleReadLoopResponse(re) default: } return nil, cs.resetErr case err := <-bodyWriter.resc: + select { case re := <-readLoopResCh: - return reFunc(re) + return handleReadLoopResponse(re) default: } if err != nil { @@ -5670,26 +5731,29 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos } } + if sentEnd { + + return nil + } + + var trls []byte + if hasTrailers { + cc.mu.Lock() + defer cc.mu.Unlock() + trls = cc.encodeTrailers(req) + } + cc.wmu.Lock() - if !sentEnd { - var trls []byte - if hasTrailers { - cc.mu.Lock() - trls = cc.encodeTrailers(req) - cc.mu.Unlock() - } + defer cc.wmu.Unlock() - if len(trls) > 0 { - err = cc.writeHeaders(cs.ID, true, trls) - } else { - err = cc.fr.WriteData(cs.ID, true, nil) - } + if len(trls) > 0 { + err = cc.writeHeaders(cs.ID, true, trls) + } else { + err = cc.fr.WriteData(cs.ID, true, nil) } if ferr := cc.bw.Flush(); ferr != nil && err == nil { err = ferr } - cc.wmu.Unlock() - return err } @@ -5918,6 +5982,14 @@ func (e http2GoAwayError) Error() string { e.LastStreamID, e.ErrCode, e.DebugData) } +func http2isEOFOrNetReadError(err error) bool { + if err == io.EOF { + return true + } + ne, ok := err.(*net.OpError) + return ok && ne.Op == "read" +} + func (rl *http2clientConnReadLoop) cleanup() { cc := rl.cc defer cc.tconn.Close() @@ -5926,16 +5998,14 @@ func (rl *http2clientConnReadLoop) cleanup() { err := cc.readerErr cc.mu.Lock() - if err == io.EOF { - if cc.goAway != nil { - err = http2GoAwayError{ - LastStreamID: cc.goAway.LastStreamID, - ErrCode: cc.goAway.ErrCode, - DebugData: cc.goAwayDebug, - } - } else { - err = io.ErrUnexpectedEOF + if cc.goAway != nil && http2isEOFOrNetReadError(err) { + err = http2GoAwayError{ + LastStreamID: cc.goAway.LastStreamID, + ErrCode: cc.goAway.ErrCode, + DebugData: cc.goAwayDebug, } + } else if err == io.EOF { + err = io.ErrUnexpectedEOF } for _, cs := range rl.activeRes { cs.bufPipe.CloseWithError(err) @@ -5954,16 +6024,21 @@ func (rl *http2clientConnReadLoop) cleanup() { func (rl *http2clientConnReadLoop) run() error { cc := rl.cc - rl.closeWhenIdle = cc.t.disableKeepAlives() + rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse gotReply := false + gotSettings := false for { f, err := cc.fr.ReadFrame() if err != nil { - cc.vlogf("Transport readFrame error: (%T) %v", err, err) + cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err) } if se, ok := err.(http2StreamError); ok { if cs := cc.streamByID(se.StreamID, true); cs != nil { - rl.endStreamError(cs, cc.fr.errDetail) + cs.cc.writeStreamReset(cs.ID, se.Code, err) + if se.Cause == nil { + se.Cause = cc.fr.errDetail + } + rl.endStreamError(cs, se) } continue } else if err != nil { @@ -5972,6 +6047,13 @@ func (rl *http2clientConnReadLoop) run() error { if http2VerboseLogs { cc.vlogf("http2: Transport received %s", http2summarizeFrame(f)) } + if !gotSettings { + if _, ok := f.(*http2SettingsFrame); !ok { + cc.logf("protocol error: received %T before a SETTINGS frame", f) + return http2ConnectionError(http2ErrCodeProtocol) + } + gotSettings = true + } maybeIdle := false switch f := f.(type) { @@ -6000,6 +6082,9 @@ func (rl *http2clientConnReadLoop) run() error { cc.logf("Transport: unhandled response frame type %T", f) } if err != nil { + if http2VerboseLogs { + cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, http2summarizeFrame(f), err) + } return err } if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 { @@ -6238,10 +6323,27 @@ var http2errClosedResponseBody = errors.New("http2: response body closed") func (b http2transportResponseBody) Close() error { cs := b.cs - if cs.bufPipe.Err() != io.EOF { + cc := cs.cc - cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil) + serverSentStreamEnd := cs.bufPipe.Err() == io.EOF + unread := cs.bufPipe.Len() + + if unread > 0 || !serverSentStreamEnd { + cc.mu.Lock() + cc.wmu.Lock() + if !serverSentStreamEnd { + cc.fr.WriteRSTStream(cs.ID, http2ErrCodeCancel) + } + + if unread > 0 { + cc.inflow.add(int32(unread)) + cc.fr.WriteWindowUpdate(0, uint32(unread)) + } + cc.bw.Flush() + cc.wmu.Unlock() + cc.mu.Unlock() } + cs.bufPipe.BreakWithError(http2errClosedResponseBody) return nil } @@ -6249,6 +6351,7 @@ func (b http2transportResponseBody) Close() error { func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error { cc := rl.cc cs := cc.streamByID(f.StreamID, f.StreamEnded()) + data := f.Data() if cs == nil { cc.mu.Lock() neverSent := cc.nextStreamID @@ -6259,27 +6362,49 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error { return http2ConnectionError(http2ErrCodeProtocol) } + if f.Length > 0 { + cc.mu.Lock() + cc.inflow.add(int32(f.Length)) + cc.mu.Unlock() + + cc.wmu.Lock() + cc.fr.WriteWindowUpdate(0, uint32(f.Length)) + cc.bw.Flush() + cc.wmu.Unlock() + } return nil } - if data := f.Data(); len(data) > 0 { - if cs.bufPipe.b == nil { + if f.Length > 0 { + if len(data) > 0 && cs.bufPipe.b == nil { cc.logf("http2: Transport received DATA frame for closed stream; closing connection") return http2ConnectionError(http2ErrCodeProtocol) } cc.mu.Lock() - if cs.inflow.available() >= int32(len(data)) { - cs.inflow.take(int32(len(data))) + if cs.inflow.available() >= int32(f.Length) { + cs.inflow.take(int32(f.Length)) } else { cc.mu.Unlock() return http2ConnectionError(http2ErrCodeFlowControl) } + + if pad := int32(f.Length) - int32(len(data)); pad > 0 { + cs.inflow.add(pad) + cc.inflow.add(pad) + cc.wmu.Lock() + cc.fr.WriteWindowUpdate(0, uint32(pad)) + cc.fr.WriteWindowUpdate(cs.ID, uint32(pad)) + cc.bw.Flush() + cc.wmu.Unlock() + } cc.mu.Unlock() - if _, err := cs.bufPipe.Write(data); err != nil { - rl.endStreamError(cs, err) - return err + if len(data) > 0 { + if _, err := cs.bufPipe.Write(data); err != nil { + rl.endStreamError(cs, err) + return err + } } } @@ -6304,9 +6429,14 @@ func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err err } cs.bufPipe.closeWithErrorAndCode(err, code) delete(rl.activeRes, cs.ID) - if cs.req.Close || cs.req.Header.Get("Connection") == "close" { + if http2isConnectionCloseRequest(cs.req) { rl.closeWhenIdle = true } + + select { + case cs.resc <- http2resAndError{err: err}: + default: + } } func (cs *http2clientStream) copyTrailers() { @@ -6334,7 +6464,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error cc := rl.cc cc.mu.Lock() defer cc.mu.Unlock() - return f.ForeachSetting(func(s http2Setting) error { + + if f.IsAck() { + if cc.wantSettingsAck { + cc.wantSettingsAck = false + return nil + } + return http2ConnectionError(http2ErrCodeProtocol) + } + + err := f.ForeachSetting(func(s http2Setting) error { switch s.ID { case http2SettingMaxFrameSize: cc.maxFrameSize = s.Val @@ -6342,6 +6481,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error cc.maxConcurrentStreams = s.Val case http2SettingInitialWindowSize: + if s.Val > math.MaxInt32 { + return http2ConnectionError(http2ErrCodeFlowControl) + } + + delta := int32(s.Val) - int32(cc.initialWindowSize) + for _, cs := range cc.streams { + cs.flow.add(delta) + } + cc.cond.Broadcast() + cc.initialWindowSize = s.Val default: @@ -6349,6 +6498,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error } return nil }) + if err != nil { + return err + } + + cc.wmu.Lock() + defer cc.wmu.Unlock() + + cc.fr.WriteSettingsAck() + cc.bw.Flush() + return cc.werr } func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame) error { @@ -6382,7 +6541,7 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er case <-cs.peerReset: default: - err := http2StreamError{cs.ID, f.ErrCode} + err := http2streamError(cs.ID, f.ErrCode) cs.resetErr = err close(cs.peerReset) cs.bufPipe.CloseWithError(err) @@ -6560,6 +6719,12 @@ func (s http2bodyWriterState) scheduleBodyWrite() { } } +// isConnectionCloseRequest reports whether req should use its own +// connection for a single request and then close the connection. +func http2isConnectionCloseRequest(req *Request) bool { + return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close") +} + // writeFramer is implemented by any type that is used to write frames. type http2writeFramer interface { writeFrame(http2writeContext) error diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index 139ce3e..13e5f28 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -4716,3 +4716,14 @@ func BenchmarkCloseNotifier(b *testing.B) { } b.StopTimer() } + +// Verify this doesn't race (Issue 16505) +func TestConcurrentServerServe(t *testing.T) { + for i := 0; i < 100; i++ { + ln1 := &oneConnListener{conn: nil} + ln2 := &oneConnListener{conn: nil} + srv := Server{} + go func() { srv.Serve(ln1) }() + go func() { srv.Serve(ln2) }() + } +} diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go index 7b2b4b2..89574a8b 100644 --- a/libgo/go/net/http/server.go +++ b/libgo/go/net/http/server.go @@ -2129,8 +2129,8 @@ type Server struct { ErrorLog *log.Logger disableKeepAlives int32 // accessed atomically. - nextProtoOnce sync.Once // guards initialization of TLSNextProto in Serve - nextProtoErr error + nextProtoOnce sync.Once // guards setupHTTP2_* init + nextProtoErr error // result of http2.ConfigureServer if used } // A ConnState represents the state of a client connection to a server. @@ -2260,10 +2260,8 @@ func (srv *Server) Serve(l net.Listener) error { } var tempDelay time.Duration // how long to sleep on accept failure - if srv.shouldConfigureHTTP2ForServe() { - if err := srv.setupHTTP2(); err != nil { - return err - } + if err := srv.setupHTTP2_Serve(); err != nil { + return err } // TODO: allow changing base context? can't imagine concrete @@ -2408,7 +2406,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { // Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig // before we clone it and create the TLS Listener. - if err := srv.setupHTTP2(); err != nil { + if err := srv.setupHTTP2_ListenAndServeTLS(); err != nil { return err } @@ -2436,14 +2434,36 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { return srv.Serve(tlsListener) } -func (srv *Server) setupHTTP2() error { +// setupHTTP2_ListenAndServeTLS conditionally configures HTTP/2 on +// srv and returns whether there was an error setting it up. If it is +// not configured for policy reasons, nil is returned. +func (srv *Server) setupHTTP2_ListenAndServeTLS() error { srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults) return srv.nextProtoErr } +// setupHTTP2_Serve is called from (*Server).Serve and conditionally +// configures HTTP/2 on srv using a more conservative policy than +// setupHTTP2_ListenAndServeTLS because Serve may be called +// concurrently. +// +// The tests named TestTransportAutomaticHTTP2* and +// TestConcurrentServerServe in server_test.go demonstrate some +// of the supported use cases and motivations. +func (srv *Server) setupHTTP2_Serve() error { + srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults_Serve) + return srv.nextProtoErr +} + +func (srv *Server) onceSetNextProtoDefaults_Serve() { + if srv.shouldConfigureHTTP2ForServe() { + srv.onceSetNextProtoDefaults() + } +} + // onceSetNextProtoDefaults configures HTTP/2, if the user hasn't // configured otherwise. (by setting srv.TLSNextProto non-nil) -// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2). +// It must only be called via srv.nextProtoOnce (use srv.setupHTTP2_*). func (srv *Server) onceSetNextProtoDefaults() { if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") { return diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index 9164d0d..1f07634 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -383,6 +383,11 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { return resp, nil } if !pconn.shouldRetryRequest(req, err) { + // Issue 16465: return underlying net.Conn.Read error from peek, + // as we've historically done. + if e, ok := err.(transportReadFromServerError); ok { + err = e.err + } return nil, err } testHookRoundTripRetried() @@ -393,6 +398,15 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { // HTTP request on a new connection. The non-nil input error is the // error from roundTrip. func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool { + if err == http2ErrNoCachedConn { + // Issue 16582: if the user started a bunch of + // requests at once, they can all pick the same conn + // and violate the server's max concurrent streams. + // Instead, match the HTTP/1 behavior for now and dial + // again to get a new TCP connection, rather than failing + // this request. + return true + } if err == errMissingHost { // User error. return false @@ -415,11 +429,19 @@ func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool { // first, per golang.org/issue/15723 return false } - if _, ok := err.(nothingWrittenError); ok { + switch err.(type) { + case nothingWrittenError: // We never wrote anything, so it's safe to retry. return true + case transportReadFromServerError: + // We got some non-EOF net.Conn.Read failure reading + // the 1st response byte from the server. + return true } - if err == errServerClosedIdle || err == errServerClosedConn { + if err == errServerClosedIdle { + // The server replied with io.EOF while we were trying to + // read the response. Probably an unfortunately keep-alive + // timeout, just as the client was writing a request. return true } return false // conservatively @@ -476,8 +498,9 @@ func (t *Transport) CloseIdleConnections() { // CancelRequest cancels an in-flight request by closing its connection. // CancelRequest should only be called after RoundTrip has returned. // -// Deprecated: Use Request.Cancel instead. CancelRequest cannot cancel -// HTTP/2 requests. +// Deprecated: Use Request.WithContext to create a request with a +// cancelable context instead. CancelRequest cannot cancel HTTP/2 +// requests. func (t *Transport) CancelRequest(req *Request) { t.reqMu.Lock() cancel := t.reqCanceler[req] @@ -566,10 +589,26 @@ var ( errCloseIdleConns = errors.New("http: CloseIdleConnections called") errReadLoopExiting = errors.New("http: persistConn.readLoop exiting") errServerClosedIdle = errors.New("http: server closed idle connection") - errServerClosedConn = errors.New("http: server closed connection") errIdleConnTimeout = errors.New("http: idle connection timeout") + errNotCachingH2Conn = errors.New("http: not caching alternate protocol's connections") ) +// transportReadFromServerError is used by Transport.readLoop when the +// 1 byte peek read fails and we're actually anticipating a response. +// Usually this is just due to the inherent keep-alive shut down race, +// where the server closed the connection at the same time the client +// wrote. The underlying err field is usually io.EOF or some +// ECONNRESET sort of thing which varies by platform. But it might be +// the user's custom net.Conn.Read error too, so we carry it along for +// them to return from Transport.RoundTrip. +type transportReadFromServerError struct { + err error +} + +func (e transportReadFromServerError) Error() string { + return fmt.Sprintf("net/http: Transport failed to read from server: %v", e.err) +} + func (t *Transport) putOrCloseIdleConn(pconn *persistConn) { if err := t.tryPutIdleConn(pconn); err != nil { pconn.close(err) @@ -595,6 +634,9 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error { if pconn.isBroken() { return errConnBroken } + if pconn.alt != nil { + return errNotCachingH2Conn + } pconn.markReused() key := pconn.cacheKey @@ -1293,7 +1335,10 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er if pc.isCanceled() { return errRequestCanceled } - if err == errServerClosedIdle || err == errServerClosedConn { + if err == errServerClosedIdle { + return err + } + if _, ok := err.(transportReadFromServerError); ok { return err } if pc.isBroken() { @@ -1314,7 +1359,11 @@ func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) err return errRequestCanceled } err := pc.closed - if err == errServerClosedIdle || err == errServerClosedConn { + if err == errServerClosedIdle { + // Don't decorate + return err + } + if _, ok := err.(transportReadFromServerError); ok { // Don't decorate return err } @@ -1383,7 +1432,7 @@ func (pc *persistConn) readLoop() { if err == nil { resp, err = pc.readResponse(rc, trace) } else { - err = errServerClosedConn + err = transportReadFromServerError{err} closeErr = err } @@ -1784,6 +1833,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err var re responseAndError var respHeaderTimer <-chan time.Time cancelChan := req.Request.Cancel + ctxDoneChan := req.Context().Done() WaitResponse: for { testHookWaitResLoop() @@ -1815,9 +1865,11 @@ WaitResponse: case <-cancelChan: pc.t.CancelRequest(req.Request) cancelChan = nil - case <-req.Context().Done(): + ctxDoneChan = nil + case <-ctxDoneChan: pc.t.CancelRequest(req.Request) cancelChan = nil + ctxDoneChan = nil } } diff --git a/libgo/go/net/http/transport_internal_test.go b/libgo/go/net/http/transport_internal_test.go index a157d90..a05ca6e 100644 --- a/libgo/go/net/http/transport_internal_test.go +++ b/libgo/go/net/http/transport_internal_test.go @@ -46,17 +46,22 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) { conn.Close() // simulate the server hanging up on the client _, err = pc.roundTrip(treq) - if err != errServerClosedConn && err != errServerClosedIdle { + if !isTransportReadFromServerError(err) && err != errServerClosedIdle { t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err) } <-pc.closech err = pc.closed - if err != errServerClosedConn && err != errServerClosedIdle { + if !isTransportReadFromServerError(err) && err != errServerClosedIdle { t.Fatalf("pc.closed = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err) } } +func isTransportReadFromServerError(err error) bool { + _, ok := err.(transportReadFromServerError) + return ok +} + func newLocalListener(t *testing.T) net.Listener { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go index 72b98f1..298682d 100644 --- a/libgo/go/net/http/transport_test.go +++ b/libgo/go/net/http/transport_test.go @@ -3511,6 +3511,100 @@ func TestTransportIdleConnTimeout(t *testing.T) { } } +// Issue 16208: Go 1.7 crashed after Transport.IdleConnTimeout if an +// HTTP/2 connection was established but but its caller no longer +// wanted it. (Assuming the connection cache was enabled, which it is +// by default) +// +// This test reproduced the crash by setting the IdleConnTimeout low +// (to make the test reasonable) and then making a request which is +// canceled by the DialTLS hook, which then also waits to return the +// real connection until after the RoundTrip saw the error. Then we +// know the successful tls.Dial from DialTLS will need to go into the +// idle pool. Then we give it a of time to explode. +func TestIdleConnH2Crash(t *testing.T) { + cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) { + // nothing + })) + defer cst.close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + gotErr := make(chan bool, 1) + + cst.tr.IdleConnTimeout = 5 * time.Millisecond + cst.tr.DialTLS = func(network, addr string) (net.Conn, error) { + cancel() + <-gotErr + c, err := tls.Dial(network, addr, &tls.Config{ + InsecureSkipVerify: true, + NextProtos: []string{"h2"}, + }) + if err != nil { + t.Error(err) + return nil, err + } + if cs := c.ConnectionState(); cs.NegotiatedProtocol != "h2" { + t.Errorf("protocol = %q; want %q", cs.NegotiatedProtocol, "h2") + c.Close() + return nil, errors.New("bogus") + } + return c, nil + } + + req, _ := NewRequest("GET", cst.ts.URL, nil) + req = req.WithContext(ctx) + res, err := cst.c.Do(req) + if err == nil { + res.Body.Close() + t.Fatal("unexpected success") + } + gotErr <- true + + // Wait for the explosion. + time.Sleep(cst.tr.IdleConnTimeout * 10) +} + +type funcConn struct { + net.Conn + read func([]byte) (int, error) + write func([]byte) (int, error) +} + +func (c funcConn) Read(p []byte) (int, error) { return c.read(p) } +func (c funcConn) Write(p []byte) (int, error) { return c.write(p) } +func (c funcConn) Close() error { return nil } + +// Issue 16465: Transport.RoundTrip should return the raw net.Conn.Read error from Peek +// back to the caller. +func TestTransportReturnsPeekError(t *testing.T) { + errValue := errors.New("specific error value") + + wrote := make(chan struct{}) + var wroteOnce sync.Once + + tr := &Transport{ + Dial: func(network, addr string) (net.Conn, error) { + c := funcConn{ + read: func([]byte) (int, error) { + <-wrote + return 0, errValue + }, + write: func(p []byte) (int, error) { + wroteOnce.Do(func() { close(wrote) }) + return len(p), nil + }, + } + return c, nil + }, + } + _, err := tr.RoundTrip(httptest.NewRequest("GET", "http://fake.tld/", nil)) + if err != errValue { + t.Errorf("error = %#v; want %v", err, errValue) + } +} + var errFakeRoundTrip = errors.New("fake roundtrip") type funcRoundTripper func() diff --git a/libgo/go/os/wait_waitid.go b/libgo/go/os/wait_waitid.go index 5dbd7f9..74b7494 100644 --- a/libgo/go/os/wait_waitid.go +++ b/libgo/go/os/wait_waitid.go @@ -28,6 +28,12 @@ func (p *Process) blockUntilWaitable() (bool, error) { _, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0) runtime.KeepAlive(psig) if e != 0 { + // waitid has been available since Linux 2.6.9, but + // reportedly is not available in Ubuntu on Windows. + // See issue 16610. + if e == syscall.ENOSYS { + return false, nil + } return false, NewSyscallError("waitid", e) } return true, nil diff --git a/libgo/go/path/filepath/export_windows_test.go b/libgo/go/path/filepath/export_windows_test.go index 8ca007f..a7e2e64 100644 --- a/libgo/go/path/filepath/export_windows_test.go +++ b/libgo/go/path/filepath/export_windows_test.go @@ -4,4 +4,7 @@ package filepath -var ToNorm = toNorm +var ( + ToNorm = toNorm + NormBase = normBase +) diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index 4d5e3bd..9c3f287 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -843,7 +843,7 @@ func TestEvalSymlinks(t *testing.T) { if p, err := filepath.EvalSymlinks(path); err != nil { t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) } else if filepath.Clean(p) != filepath.Clean(dest) { - t.Errorf("Clean(%q)=%q, want %q", path, p, dest) + t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest) } // test EvalSymlinks(".") @@ -875,6 +875,34 @@ func TestEvalSymlinks(t *testing.T) { t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want) }() + // test EvalSymlinks(".."+path) + func() { + defer func() { + err := os.Chdir(wd) + if err != nil { + t.Fatal(err) + } + }() + + err := os.Chdir(simpleJoin(tmpDir, "test")) + if err != nil { + t.Error(err) + return + } + + path := simpleJoin("..", d.path) + dest := simpleJoin("..", d.dest) + if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) { + dest = d.dest + } + + if p, err := filepath.EvalSymlinks(path); err != nil { + t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) + } else if filepath.Clean(p) != filepath.Clean(dest) { + t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest) + } + }() + // test EvalSymlinks where parameter is relative path func() { defer func() { @@ -892,7 +920,7 @@ func TestEvalSymlinks(t *testing.T) { if p, err := filepath.EvalSymlinks(d.path); err != nil { t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) } else if filepath.Clean(p) != filepath.Clean(d.dest) { - t.Errorf("Clean(%q)=%q, want %q", d.path, p, d.dest) + t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest) } }() } diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go index 2433528..bb05aab 100644 --- a/libgo/go/path/filepath/symlink_windows.go +++ b/libgo/go/path/filepath/symlink_windows.go @@ -22,7 +22,7 @@ func normVolumeName(path string) string { return strings.ToUpper(volume) } -// normBase retruns the last element of path. +// normBase returns the last element of path with correct case. func normBase(path string) (string, error) { p, err := syscall.UTF16PtrFromString(path) if err != nil { @@ -40,7 +40,24 @@ func normBase(path string) (string, error) { return syscall.UTF16ToString(data.FileName[:]), nil } -func toNorm(path string, base func(string) (string, error)) (string, error) { +// baseIsDotDot returns whether the last element of path is "..". +// The given path should be 'Clean'-ed in advance. +func baseIsDotDot(path string) bool { + i := strings.LastIndexByte(path, Separator) + return path[i+1:] == ".." +} + +// toNorm returns the normalized path that is guranteed to be unique. +// It should accept the following formats: +// * UNC paths (e.g \\server\share\foo\bar) +// * absolute paths (e.g C:\foo\bar) +// * relative paths begin with drive letter (e.g C:foo\bar, C:..\foo\bar, C:.., C:.) +// * relative paths begin with '\' (e.g \foo\bar) +// * relative paths begin without '\' (e.g foo\bar, ..\foo\bar, .., .) +// The returned normalized path will be in the same form (of 5 listed above) as the input path. +// If two paths A and B are indicating the same file with the same format, toNorm(A) should be equal to toNorm(B). +// The normBase parameter should be equal to the normBase func, except for in tests. See docs on the normBase func. +func toNorm(path string, normBase func(string) (string, error)) (string, error) { if path == "" { return path, nil } @@ -58,7 +75,13 @@ func toNorm(path string, base func(string) (string, error)) (string, error) { var normPath string for { - name, err := base(volume + path) + if baseIsDotDot(path) { + normPath = path + `\` + normPath + + break + } + + name, err := normBase(volume + path) if err != nil { return "", err } diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 7045e44..e601c2c 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -5752,6 +5752,8 @@ func TestTypeStrings(t *testing.T) { {TypeOf(new(XM)), "*reflect_test.XM"}, {TypeOf(new(XM).String), "func() string"}, {TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"}, + {ChanOf(3, TypeOf(XM{})), "chan reflect_test.XM"}, + {MapOf(TypeOf(int(0)), TypeOf(XM{})), "map[int]reflect_test.XM"}, } for i, test := range stringTests { diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go index d2e5b63..0a58baf 100644 --- a/libgo/go/runtime/pprof/pprof.go +++ b/libgo/go/runtime/pprof/pprof.go @@ -4,8 +4,69 @@ // Package pprof writes runtime profiling data in the format expected // by the pprof visualization tool. +// +// Profiling a Go program +// +// The first step to profiling a Go program is to enable profiling. +// Support for profiling benchmarks built with the standard testing +// package is built into go test. For example, the following command +// runs benchmarks in the current directory and writes the CPU and +// memory profiles to cpu.prof and mem.prof: +// +// go test -cpuprofile cpu.prof -memprofile mem.prof -bench . +// +// To add equivalent profiling support to a standalone program, add +// code like the following to your main function: +// +// var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`") +// var memprofile = flag.String("memprofile", "", "write memory profile to `file`") +// +// func main() { +// flag.Parse() +// if *cpuprofile != "" { +// f, err := os.Create(*cpuprofile) +// if err != nil { +// log.Fatal("could not create CPU profile: ", err) +// } +// if err := pprof.StartCPUProfile(f); err != nil { +// log.Fatal("could not start CPU profile: ", err) +// } +// defer pprof.StopCPUProfile() +// } +// ... +// if *memprofile != "" { +// f, err := os.Create(*memprofile) +// if err != nil { +// log.Fatal("could not create memory profile: ", err) +// } +// runtime.GC() // get up-to-date statistics +// if err := pprof.WriteHeapProfile(f); err != nil { +// log.Fatal("could not write memory profile: ", err) +// } +// f.Close() +// } +// } +// +// There is also a standard HTTP interface to profiling data. Adding +// the following line will install handlers under the /debug/pprof/ +// URL to download live profiles: +// +// import _ "net/http/pprof" +// +// See the net/http/pprof package for more details. +// +// Profiles can then be visualized with the pprof tool: +// +// go tool pprof cpu.prof +// +// There are many commands available from the pprof command line. +// Commonly used commands include "top", which prints a summary of the +// top program hot-spots, and "web", which opens an interactive graph +// of hot-spots and their call graphs. Use "help" for information on +// all pprof commands. +// // For more information about pprof, see -// http://github.com/google/pprof/. +// https://github.com/google/pprof/blob/master/doc/pprof.md. package pprof import ( diff --git a/libgo/go/syscall/syscall_darwin_test.go b/libgo/go/syscall/syscall_darwin_test.go new file mode 100644 index 0000000..cea5636 --- /dev/null +++ b/libgo/go/syscall/syscall_darwin_test.go @@ -0,0 +1,23 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin +// +build amd64 386 arm arm64 + +package syscall_test + +import ( + "syscall" + "testing" +) + +func TestDarwinGettimeofday(t *testing.T) { + tv := &syscall.Timeval{} + if err := syscall.Gettimeofday(tv); err != nil { + t.Fatal(err) + } + if tv.Sec == 0 && tv.Usec == 0 { + t.Fatal("Sec and Usec both zero") + } +} |