Commit af4b8a52 by Ian Lance Taylor

libgo: update to Go 1.7.1 release

    
    Reviewed-on: https://go-review.googlesource.com/29012

From-SVN: r240071
parent 337fa50b
04fe765560107e5d4c5f98c1022765930a1069f9 d3a145b111a4f4ea772b812c6a0b3a853c207819
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
8707f31c0abc6b607014e843b7cc188b3019daa9 f75aafdf56dd90eab75cfeac8cf69358f73ba171
The first line of this file holds the git revision number of the The first line of this file holds the git revision number of the
last merge done from the master library sources. last merge done from the master library sources.
...@@ -15,7 +15,17 @@ const ( ...@@ -15,7 +15,17 @@ const (
BestSpeed = 1 BestSpeed = 1
BestCompression = 9 BestCompression = 9
DefaultCompression = -1 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 ( const (
...@@ -644,7 +654,6 @@ func (d *compressor) close() error { ...@@ -644,7 +654,6 @@ func (d *compressor) close() error {
// a very fast compression for all types of input, but sacrificing considerable // a very fast compression for all types of input, but sacrificing considerable
// compression efficiency. // compression efficiency.
// //
//
// If level is in the range [-2, 9] then the error returned will be nil. // If level is in the range [-2, 9] then the error returned will be nil.
// Otherwise the error returned will be non-nil. // Otherwise the error returned will be non-nil.
func NewWriter(w io.Writer, level int) (*Writer, error) { func NewWriter(w io.Writer, level int) (*Writer, error) {
...@@ -715,7 +724,7 @@ func (w *Writer) Close() error { ...@@ -715,7 +724,7 @@ func (w *Writer) Close() error {
// the result of NewWriter or NewWriterDict called with dst // the result of NewWriter or NewWriterDict called with dst
// and w's level and dictionary. // and w's level and dictionary.
func (w *Writer) Reset(dst io.Writer) { 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 // w was created with NewWriterDict
dw.w = dst dw.w = dst
w.d.reset(dw) w.d.reset(dw)
......
...@@ -6,6 +6,7 @@ package flate ...@@ -6,6 +6,7 @@ package flate
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"internal/testenv" "internal/testenv"
"io" "io"
...@@ -631,3 +632,52 @@ func TestBestSpeed(t *testing.T) { ...@@ -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
}
}
}
...@@ -77,7 +77,11 @@ var offsetBase = []uint32{ ...@@ -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} 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 { 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] // Data waiting to be written is bytes[0:nbytes]
// and then the low nbits of bits. // and then the low nbits of bits.
bits uint64 bits uint64
...@@ -96,7 +100,7 @@ type huffmanBitWriter struct { ...@@ -96,7 +100,7 @@ type huffmanBitWriter struct {
func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
return &huffmanBitWriter{ return &huffmanBitWriter{
w: w, writer: w,
literalFreq: make([]int32, maxNumLit), literalFreq: make([]int32, maxNumLit),
offsetFreq: make([]int32, offsetCodeCount), offsetFreq: make([]int32, offsetCodeCount),
codegen: make([]uint8, maxNumLit+offsetCodeCount+1), codegen: make([]uint8, maxNumLit+offsetCodeCount+1),
...@@ -107,7 +111,7 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { ...@@ -107,7 +111,7 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
} }
func (w *huffmanBitWriter) reset(writer io.Writer) { 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.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil
w.bytes = [bufferSize]byte{} w.bytes = [bufferSize]byte{}
} }
...@@ -129,11 +133,21 @@ func (w *huffmanBitWriter) flush() { ...@@ -129,11 +133,21 @@ func (w *huffmanBitWriter) flush() {
n++ n++
} }
w.bits = 0 w.bits = 0
_, w.err = w.w.Write(w.bytes[:n]) w.write(w.bytes[:n])
w.nbytes = 0 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) { func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
if w.err != nil {
return
}
w.bits |= uint64(b) << w.nbits w.bits |= uint64(b) << w.nbits
w.nbits += nb w.nbits += nb
if w.nbits >= 48 { if w.nbits >= 48 {
...@@ -150,7 +164,7 @@ func (w *huffmanBitWriter) writeBits(b int32, nb uint) { ...@@ -150,7 +164,7 @@ func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
bytes[5] = byte(bits >> 40) bytes[5] = byte(bits >> 40)
n += 6 n += 6
if n >= bufferFlushSize { if n >= bufferFlushSize {
_, w.err = w.w.Write(w.bytes[:n]) w.write(w.bytes[:n])
n = 0 n = 0
} }
w.nbytes = n w.nbytes = n
...@@ -173,13 +187,10 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) { ...@@ -173,13 +187,10 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
n++ n++
} }
if n != 0 { if n != 0 {
_, w.err = w.w.Write(w.bytes[:n]) w.write(w.bytes[:n])
if w.err != nil {
return
}
} }
w.nbytes = 0 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 // RFC 1951 3.2.7 specifies a special run-length encoding for specifying
...@@ -341,7 +352,7 @@ func (w *huffmanBitWriter) writeCode(c hcode) { ...@@ -341,7 +352,7 @@ func (w *huffmanBitWriter) writeCode(c hcode) {
bytes[5] = byte(bits >> 40) bytes[5] = byte(bits >> 40)
n += 6 n += 6
if n >= bufferFlushSize { if n >= bufferFlushSize {
_, w.err = w.w.Write(w.bytes[:n]) w.write(w.bytes[:n])
n = 0 n = 0
} }
w.nbytes = n w.nbytes = n
...@@ -572,6 +583,9 @@ func (w *huffmanBitWriter) indexTokens(tokens []token) (numLiterals, numOffsets ...@@ -572,6 +583,9 @@ func (w *huffmanBitWriter) indexTokens(tokens []token) (numLiterals, numOffsets
// writeTokens writes a slice of tokens to the output. // writeTokens writes a slice of tokens to the output.
// codes for literal and offset encoding must be supplied. // codes for literal and offset encoding must be supplied.
func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) { func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) {
if w.err != nil {
return
}
for _, t := range tokens { for _, t := range tokens {
if t < matchType { if t < matchType {
w.writeCode(leCodes[t.literal()]) w.writeCode(leCodes[t.literal()])
...@@ -676,9 +690,9 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) { ...@@ -676,9 +690,9 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) {
if n < bufferFlushSize { if n < bufferFlushSize {
continue continue
} }
_, w.err = w.w.Write(w.bytes[:n]) w.write(w.bytes[:n])
if w.err != nil { if w.err != nil {
return return // Return early in the event of write failures
} }
n = 0 n = 0
} }
......
...@@ -255,6 +255,12 @@ func TestDeadline(t *testing.T) { ...@@ -255,6 +255,12 @@ func TestDeadline(t *testing.T) {
o = otherContext{c} o = otherContext{c}
c, _ = WithDeadline(o, time.Now().Add(4*time.Second)) c, _ = WithDeadline(o, time.Now().Add(4*time.Second))
testDeadline(c, "WithDeadline+otherContext+WithDeadline", 2*time.Second, t) 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) { func TestTimeout(t *testing.T) {
......
...@@ -10,9 +10,65 @@ package x509 ...@@ -10,9 +10,65 @@ package x509
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060 #cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
#cgo LDFLAGS: -framework CoreFoundation -framework Security #cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <errno.h>
#include <sys/sysctl.h>
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.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. // 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 // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
...@@ -21,6 +77,10 @@ package x509 ...@@ -21,6 +77,10 @@ package x509
// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after // Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
// we've consumed its content. // we've consumed its content.
int FetchPEMRoots(CFDataRef *pemRoots) { int FetchPEMRoots(CFDataRef *pemRoots) {
if (useOldCode()) {
return FetchPEMRoots_MountainLion(pemRoots);
}
// Get certificates from all domains, not just System, this lets // Get certificates from all domains, not just System, this lets
// the user add CAs to their "login" keychain, and Admins to add // the user add CAs to their "login" keychain, and Admins to add
// to the "System" keychain // to the "System" keychain
......
...@@ -6,14 +6,9 @@ ...@@ -6,14 +6,9 @@
package crc32 package crc32
import (
"unsafe"
)
const ( const (
vxMinLen = 64 vxMinLen = 64
vxAlignment = 16 vxAlignMask = 15 // align to 16 bytes
vxAlignMask = vxAlignment - 1
) )
// hasVectorFacility reports whether the machine has the z/Architecture // hasVectorFacility reports whether the machine has the z/Architecture
...@@ -51,20 +46,13 @@ func genericIEEE(crc uint32, p []byte) uint32 { ...@@ -51,20 +46,13 @@ func genericIEEE(crc uint32, p []byte) uint32 {
return update(crc, IEEETable, p) return update(crc, IEEETable, p)
} }
// updateCastagnoli calculates the checksum of p using genericCastagnoli to // updateCastagnoli calculates the checksum of p using
// align the data appropriately for vectorCastagnoli. It avoids using // vectorizedCastagnoli if possible and falling back onto
// vectorCastagnoli entirely if the length of p is less than or equal to // genericCastagnoli as needed.
// vxMinLen.
func updateCastagnoli(crc uint32, p []byte) uint32 { func updateCastagnoli(crc uint32, p []byte) uint32 {
// Use vectorized function if vector facility is available and // Use vectorized function if vector facility is available and
// data length is above threshold. // data length is above threshold.
if hasVX && len(p) > vxMinLen { 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:]
}
aligned := len(p) & ^vxAlignMask aligned := len(p) & ^vxAlignMask
crc = vectorizedCastagnoli(crc, p[:aligned]) crc = vectorizedCastagnoli(crc, p[:aligned])
p = p[aligned:] p = p[aligned:]
...@@ -77,19 +65,12 @@ func updateCastagnoli(crc uint32, p []byte) uint32 { ...@@ -77,19 +65,12 @@ func updateCastagnoli(crc uint32, p []byte) uint32 {
return genericCastagnoli(crc, p) return genericCastagnoli(crc, p)
} }
// updateIEEE calculates the checksum of p using genericIEEE to align the data // updateIEEE calculates the checksum of p using vectorizedIEEE if
// appropriately for vectorIEEE. It avoids using vectorIEEE entirely if the length // possible and falling back onto genericIEEE as needed.
// of p is less than or equal to vxMinLen.
func updateIEEE(crc uint32, p []byte) uint32 { func updateIEEE(crc uint32, p []byte) uint32 {
// Use vectorized function if vector facility is available and // Use vectorized function if vector facility is available and
// data length is above threshold. // data length is above threshold.
if hasVX && len(p) > vxMinLen { 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:]
}
aligned := len(p) & ^vxAlignMask aligned := len(p) & ^vxAlignMask
crc = vectorizedIEEE(crc, p[:aligned]) crc = vectorizedIEEE(crc, p[:aligned])
p = p[aligned:] p = p[aligned:]
......
...@@ -18,15 +18,16 @@ func (mr *multiReader) Read(p []byte) (n int, err error) { ...@@ -18,15 +18,16 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
} }
} }
n, err = mr.readers[0].Read(p) n, err = mr.readers[0].Read(p)
if err == EOF {
mr.readers = mr.readers[1:]
}
if n > 0 || err != EOF { if n > 0 || err != EOF {
if err == EOF { if err == EOF && len(mr.readers) > 0 {
// Don't return EOF yet. There may be more bytes // Don't return EOF yet. More readers remain.
// in the remaining readers.
err = nil err = nil
} }
return return
} }
mr.readers = mr.readers[1:]
} }
return 0, EOF return 0, EOF
} }
......
...@@ -197,3 +197,41 @@ func TestMultiReaderFlatten(t *testing.T) { ...@@ -197,3 +197,41 @@ func TestMultiReaderFlatten(t *testing.T) {
myDepth+2, readDepth) 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)
}
}
// 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())
}
}
...@@ -141,7 +141,7 @@ func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn, ...@@ -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. // 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() d := testHookDNSDialer()
out := dnsMsg{ out := dnsMsg{
dnsMsgHdr: dnsMsgHdr{ dnsMsgHdr: dnsMsgHdr{
...@@ -152,6 +152,12 @@ func exchange(ctx context.Context, server, name string, qtype uint16) (*dnsMsg, ...@@ -152,6 +152,12 @@ func exchange(ctx context.Context, server, name string, qtype uint16) (*dnsMsg,
}, },
} }
for _, network := range []string{"udp", "tcp"} { 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) c, err := d.dialDNS(ctx, network, server)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -180,17 +186,10 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) ...@@ -180,17 +186,10 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16)
return "", nil, &DNSError{Err: "no DNS servers", Name: name} 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 var lastErr error
for i := 0; i < cfg.attempts; i++ { for i := 0; i < cfg.attempts; i++ {
for _, server := range cfg.servers { for _, server := range cfg.servers {
msg, err := exchange(ctx, server, name, qtype) msg, err := exchange(ctx, server, name, qtype, cfg.timeout)
if err != nil { if err != nil {
lastErr = &DNSError{ lastErr = &DNSError{
Err: err.Error(), Err: err.Error(),
...@@ -338,8 +337,9 @@ func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs [ ...@@ -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 // avoidDNS reports whether this is a hostname for which we should not
// use DNS. Currently this includes only .onion and .local names, // use DNS. Currently this includes only .onion, per RFC 7686. See
// per RFC 7686 and RFC 6762, respectively. See golang.org/issue/13705. // golang.org/issue/13705. Does not cover .local names (RFC 6762),
// see golang.org/issue/16739.
func avoidDNS(name string) bool { func avoidDNS(name string) bool {
if name == "" { if name == "" {
return true return true
...@@ -347,7 +347,7 @@ func avoidDNS(name string) bool { ...@@ -347,7 +347,7 @@ func avoidDNS(name string) bool {
if name[len(name)-1] == '.' { if name[len(name)-1] == '.' {
name = 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. // nameList returns a list of names for sequential DNS queries.
......
...@@ -40,9 +40,9 @@ func TestDNSTransportFallback(t *testing.T) { ...@@ -40,9 +40,9 @@ func TestDNSTransportFallback(t *testing.T) {
testenv.MustHaveExternalNetwork(t) testenv.MustHaveExternalNetwork(t)
for _, tt := range dnsTransportFallbackTests { for _, tt := range dnsTransportFallbackTests {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(tt.timeout)*time.Second) ctx, cancel := context.WithCancel(context.Background())
defer cancel() 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 { if err != nil {
t.Error(err) t.Error(err)
continue continue
...@@ -82,9 +82,9 @@ func TestSpecialDomainName(t *testing.T) { ...@@ -82,9 +82,9 @@ func TestSpecialDomainName(t *testing.T) {
server := "8.8.8.8:53" server := "8.8.8.8:53"
for _, tt := range specialDomainNameTests { for _, tt := range specialDomainNameTests {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithCancel(context.Background())
defer cancel() 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 { if err != nil {
t.Error(err) t.Error(err)
continue continue
...@@ -112,10 +112,11 @@ func TestAvoidDNSName(t *testing.T) { ...@@ -112,10 +112,11 @@ func TestAvoidDNSName(t *testing.T) {
{"foo.ONION", true}, {"foo.ONION", true},
{"foo.ONION.", true}, {"foo.ONION.", true},
{"foo.local.", true}, // But do resolve *.local address; Issue 16739
{"foo.local", true}, {"foo.local.", false},
{"foo.LOCAL", true}, {"foo.local", false},
{"foo.LOCAL.", true}, {"foo.LOCAL", false},
{"foo.LOCAL.", false},
{"", true}, // will be rejected earlier too {"", true}, // will be rejected earlier too
...@@ -500,7 +501,7 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) { ...@@ -500,7 +501,7 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
d := &fakeDNSDialer{} d := &fakeDNSDialer{}
testHookDNSDialer = func() dnsDialer { return d } 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{ r := &dnsMsg{
dnsMsgHdr: dnsMsgHdr{ dnsMsgHdr: dnsMsgHdr{
id: q.id, id: q.id,
...@@ -539,14 +540,15 @@ func TestIgnoreLameReferrals(t *testing.T) { ...@@ -539,14 +540,15 @@ func TestIgnoreLameReferrals(t *testing.T) {
} }
defer conf.teardown() 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) t.Fatal(err)
} }
d := &fakeDNSDialer{} d := &fakeDNSDialer{}
testHookDNSDialer = func() dnsDialer { return d } 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) t.Log(s, q)
r := &dnsMsg{ r := &dnsMsg{
dnsMsgHdr: dnsMsgHdr{ dnsMsgHdr: dnsMsgHdr{
...@@ -633,28 +635,30 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) { ...@@ -633,28 +635,30 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
type fakeDNSDialer struct { type fakeDNSDialer struct {
// reply handler // 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) { 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 { type fakeDNSConn struct {
rh func(s string, q *dnsMsg) (*dnsMsg, error) rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
s string s string
t time.Time
} }
func (f *fakeDNSConn) Close() error { func (f *fakeDNSConn) Close() error {
return nil return nil
} }
func (f *fakeDNSConn) SetDeadline(time.Time) error { func (f *fakeDNSConn) SetDeadline(t time.Time) error {
f.t = t
return nil return nil
} }
func (f *fakeDNSConn) dnsRoundTrip(q *dnsMsg) (*dnsMsg, error) { 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). // UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
...@@ -724,3 +728,72 @@ func TestIgnoreDNSForgeries(t *testing.T) { ...@@ -724,3 +728,72 @@ func TestIgnoreDNSForgeries(t *testing.T) {
t.Errorf("got address %v, want %v", got, TestAddr) 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)
}
}
...@@ -64,7 +64,7 @@ func (fd *netFD) name() string { ...@@ -64,7 +64,7 @@ func (fd *netFD) name() string {
return fd.net + ":" + ls + "->" + rs 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, // Do not need to call fd.writeLock here,
// because fd is not yet accessible to user, // because fd is not yet accessible to user,
// so no concurrent operations are possible. // so no concurrent operations are possible.
...@@ -101,21 +101,44 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error { ...@@ -101,21 +101,44 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
defer fd.setWriteDeadline(noDeadline) defer fd.setWriteDeadline(noDeadline)
} }
// Wait for the goroutine converting context.Done into a write timeout // Start the "interrupter" goroutine, if this context might be canceled.
// to exist, otherwise our caller might cancel the context and // (The background context cannot)
// cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial. //
done := make(chan bool) // must be unbuffered // The interrupter goroutine waits for the context to be done and
defer func() { done <- true }() // interrupts the dial (by altering the fd's write deadline, which
go func() { // wakes up waitWrite).
select { if ctx != context.Background() {
case <-ctx.Done(): // Wait for the interrupter goroutine to exit before returning
// Force the runtime's poller to immediately give // from connect.
// up waiting for writability. done := make(chan struct{})
fd.setWriteDeadline(aLongTimeAgo) interruptRes := make(chan error)
<-done defer func() {
case <-done: 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 { for {
// Performing multiple connect system calls on a // Performing multiple connect system calls on a
......
...@@ -9,7 +9,8 @@ package net ...@@ -9,7 +9,8 @@ package net
import "syscall" import "syscall"
var ( 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. // Placeholders for socket system calls.
socketFunc func(int, int, int) (int, error) = syscall.Socket socketFunc func(int, int, int) (int, error) = syscall.Socket
......
...@@ -4716,3 +4716,14 @@ func BenchmarkCloseNotifier(b *testing.B) { ...@@ -4716,3 +4716,14 @@ func BenchmarkCloseNotifier(b *testing.B) {
} }
b.StopTimer() 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) }()
}
}
...@@ -2129,8 +2129,8 @@ type Server struct { ...@@ -2129,8 +2129,8 @@ type Server struct {
ErrorLog *log.Logger ErrorLog *log.Logger
disableKeepAlives int32 // accessed atomically. disableKeepAlives int32 // accessed atomically.
nextProtoOnce sync.Once // guards initialization of TLSNextProto in Serve nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error nextProtoErr error // result of http2.ConfigureServer if used
} }
// A ConnState represents the state of a client connection to a server. // A ConnState represents the state of a client connection to a server.
...@@ -2260,10 +2260,8 @@ func (srv *Server) Serve(l net.Listener) error { ...@@ -2260,10 +2260,8 @@ func (srv *Server) Serve(l net.Listener) error {
} }
var tempDelay time.Duration // how long to sleep on accept failure var tempDelay time.Duration // how long to sleep on accept failure
if srv.shouldConfigureHTTP2ForServe() { if err := srv.setupHTTP2_Serve(); err != nil {
if err := srv.setupHTTP2(); err != nil { return err
return err
}
} }
// TODO: allow changing base context? can't imagine concrete // TODO: allow changing base context? can't imagine concrete
...@@ -2408,7 +2406,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { ...@@ -2408,7 +2406,7 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
// Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig // Setup HTTP/2 before srv.Serve, to initialize srv.TLSConfig
// before we clone it and create the TLS Listener. // before we clone it and create the TLS Listener.
if err := srv.setupHTTP2(); err != nil { if err := srv.setupHTTP2_ListenAndServeTLS(); err != nil {
return err return err
} }
...@@ -2436,14 +2434,36 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { ...@@ -2436,14 +2434,36 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return srv.Serve(tlsListener) 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) srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults)
return srv.nextProtoErr 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 // onceSetNextProtoDefaults configures HTTP/2, if the user hasn't
// configured otherwise. (by setting srv.TLSNextProto non-nil) // 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() { func (srv *Server) onceSetNextProtoDefaults() {
if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") { if strings.Contains(os.Getenv("GODEBUG"), "http2server=0") {
return return
......
...@@ -383,6 +383,11 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { ...@@ -383,6 +383,11 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
return resp, nil return resp, nil
} }
if !pconn.shouldRetryRequest(req, err) { 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 return nil, err
} }
testHookRoundTripRetried() testHookRoundTripRetried()
...@@ -393,6 +398,15 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { ...@@ -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 // HTTP request on a new connection. The non-nil input error is the
// error from roundTrip. // error from roundTrip.
func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool { 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 { if err == errMissingHost {
// User error. // User error.
return false return false
...@@ -415,11 +429,19 @@ func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool { ...@@ -415,11 +429,19 @@ func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
// first, per golang.org/issue/15723 // first, per golang.org/issue/15723
return false return false
} }
if _, ok := err.(nothingWrittenError); ok { switch err.(type) {
case nothingWrittenError:
// We never wrote anything, so it's safe to retry. // We never wrote anything, so it's safe to retry.
return true 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 true
} }
return false // conservatively return false // conservatively
...@@ -476,8 +498,9 @@ func (t *Transport) CloseIdleConnections() { ...@@ -476,8 +498,9 @@ func (t *Transport) CloseIdleConnections() {
// CancelRequest cancels an in-flight request by closing its connection. // CancelRequest cancels an in-flight request by closing its connection.
// CancelRequest should only be called after RoundTrip has returned. // CancelRequest should only be called after RoundTrip has returned.
// //
// Deprecated: Use Request.Cancel instead. CancelRequest cannot cancel // Deprecated: Use Request.WithContext to create a request with a
// HTTP/2 requests. // cancelable context instead. CancelRequest cannot cancel HTTP/2
// requests.
func (t *Transport) CancelRequest(req *Request) { func (t *Transport) CancelRequest(req *Request) {
t.reqMu.Lock() t.reqMu.Lock()
cancel := t.reqCanceler[req] cancel := t.reqCanceler[req]
...@@ -566,10 +589,26 @@ var ( ...@@ -566,10 +589,26 @@ var (
errCloseIdleConns = errors.New("http: CloseIdleConnections called") errCloseIdleConns = errors.New("http: CloseIdleConnections called")
errReadLoopExiting = errors.New("http: persistConn.readLoop exiting") errReadLoopExiting = errors.New("http: persistConn.readLoop exiting")
errServerClosedIdle = errors.New("http: server closed idle connection") errServerClosedIdle = errors.New("http: server closed idle connection")
errServerClosedConn = errors.New("http: server closed connection")
errIdleConnTimeout = errors.New("http: idle connection timeout") 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) { func (t *Transport) putOrCloseIdleConn(pconn *persistConn) {
if err := t.tryPutIdleConn(pconn); err != nil { if err := t.tryPutIdleConn(pconn); err != nil {
pconn.close(err) pconn.close(err)
...@@ -595,6 +634,9 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error { ...@@ -595,6 +634,9 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
if pconn.isBroken() { if pconn.isBroken() {
return errConnBroken return errConnBroken
} }
if pconn.alt != nil {
return errNotCachingH2Conn
}
pconn.markReused() pconn.markReused()
key := pconn.cacheKey key := pconn.cacheKey
...@@ -1293,7 +1335,10 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er ...@@ -1293,7 +1335,10 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er
if pc.isCanceled() { if pc.isCanceled() {
return errRequestCanceled return errRequestCanceled
} }
if err == errServerClosedIdle || err == errServerClosedConn { if err == errServerClosedIdle {
return err
}
if _, ok := err.(transportReadFromServerError); ok {
return err return err
} }
if pc.isBroken() { if pc.isBroken() {
...@@ -1314,7 +1359,11 @@ func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) err ...@@ -1314,7 +1359,11 @@ func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) err
return errRequestCanceled return errRequestCanceled
} }
err := pc.closed err := pc.closed
if err == errServerClosedIdle || err == errServerClosedConn { if err == errServerClosedIdle {
// Don't decorate
return err
}
if _, ok := err.(transportReadFromServerError); ok {
// Don't decorate // Don't decorate
return err return err
} }
...@@ -1383,7 +1432,7 @@ func (pc *persistConn) readLoop() { ...@@ -1383,7 +1432,7 @@ func (pc *persistConn) readLoop() {
if err == nil { if err == nil {
resp, err = pc.readResponse(rc, trace) resp, err = pc.readResponse(rc, trace)
} else { } else {
err = errServerClosedConn err = transportReadFromServerError{err}
closeErr = err closeErr = err
} }
...@@ -1784,6 +1833,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err ...@@ -1784,6 +1833,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
var re responseAndError var re responseAndError
var respHeaderTimer <-chan time.Time var respHeaderTimer <-chan time.Time
cancelChan := req.Request.Cancel cancelChan := req.Request.Cancel
ctxDoneChan := req.Context().Done()
WaitResponse: WaitResponse:
for { for {
testHookWaitResLoop() testHookWaitResLoop()
...@@ -1815,9 +1865,11 @@ WaitResponse: ...@@ -1815,9 +1865,11 @@ WaitResponse:
case <-cancelChan: case <-cancelChan:
pc.t.CancelRequest(req.Request) pc.t.CancelRequest(req.Request)
cancelChan = nil cancelChan = nil
case <-req.Context().Done(): ctxDoneChan = nil
case <-ctxDoneChan:
pc.t.CancelRequest(req.Request) pc.t.CancelRequest(req.Request)
cancelChan = nil cancelChan = nil
ctxDoneChan = nil
} }
} }
......
...@@ -46,17 +46,22 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) { ...@@ -46,17 +46,22 @@ func TestTransportPersistConnReadLoopEOF(t *testing.T) {
conn.Close() // simulate the server hanging up on the client conn.Close() // simulate the server hanging up on the client
_, err = pc.roundTrip(treq) _, 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) t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
} }
<-pc.closech <-pc.closech
err = pc.closed 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) 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 { func newLocalListener(t *testing.T) net.Listener {
ln, err := net.Listen("tcp", "127.0.0.1:0") ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil { if err != nil {
......
...@@ -3511,6 +3511,100 @@ func TestTransportIdleConnTimeout(t *testing.T) { ...@@ -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") var errFakeRoundTrip = errors.New("fake roundtrip")
type funcRoundTripper func() type funcRoundTripper func()
......
...@@ -28,6 +28,12 @@ func (p *Process) blockUntilWaitable() (bool, error) { ...@@ -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) _, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
runtime.KeepAlive(psig) runtime.KeepAlive(psig)
if e != 0 { 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 false, NewSyscallError("waitid", e)
} }
return true, nil return true, nil
......
...@@ -4,4 +4,7 @@ ...@@ -4,4 +4,7 @@
package filepath package filepath
var ToNorm = toNorm var (
ToNorm = toNorm
NormBase = normBase
)
...@@ -843,7 +843,7 @@ func TestEvalSymlinks(t *testing.T) { ...@@ -843,7 +843,7 @@ func TestEvalSymlinks(t *testing.T) {
if p, err := filepath.EvalSymlinks(path); err != nil { if p, err := filepath.EvalSymlinks(path); err != nil {
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
} else if filepath.Clean(p) != filepath.Clean(dest) { } 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(".") // test EvalSymlinks(".")
...@@ -875,6 +875,34 @@ func TestEvalSymlinks(t *testing.T) { ...@@ -875,6 +875,34 @@ func TestEvalSymlinks(t *testing.T) {
t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want) 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 // test EvalSymlinks where parameter is relative path
func() { func() {
defer func() { defer func() {
...@@ -892,7 +920,7 @@ func TestEvalSymlinks(t *testing.T) { ...@@ -892,7 +920,7 @@ func TestEvalSymlinks(t *testing.T) {
if p, err := filepath.EvalSymlinks(d.path); err != nil { if p, err := filepath.EvalSymlinks(d.path); err != nil {
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
} else if filepath.Clean(p) != filepath.Clean(d.dest) { } 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)
} }
}() }()
} }
......
...@@ -22,7 +22,7 @@ func normVolumeName(path string) string { ...@@ -22,7 +22,7 @@ func normVolumeName(path string) string {
return strings.ToUpper(volume) 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) { func normBase(path string) (string, error) {
p, err := syscall.UTF16PtrFromString(path) p, err := syscall.UTF16PtrFromString(path)
if err != nil { if err != nil {
...@@ -40,7 +40,24 @@ func normBase(path string) (string, error) { ...@@ -40,7 +40,24 @@ func normBase(path string) (string, error) {
return syscall.UTF16ToString(data.FileName[:]), nil 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 == "" { if path == "" {
return path, nil return path, nil
} }
...@@ -58,7 +75,13 @@ func toNorm(path string, base func(string) (string, error)) (string, error) { ...@@ -58,7 +75,13 @@ func toNorm(path string, base func(string) (string, error)) (string, error) {
var normPath string var normPath string
for { for {
name, err := base(volume + path) if baseIsDotDot(path) {
normPath = path + `\` + normPath
break
}
name, err := normBase(volume + path)
if err != nil { if err != nil {
return "", err return "", err
} }
......
...@@ -5752,6 +5752,8 @@ func TestTypeStrings(t *testing.T) { ...@@ -5752,6 +5752,8 @@ func TestTypeStrings(t *testing.T) {
{TypeOf(new(XM)), "*reflect_test.XM"}, {TypeOf(new(XM)), "*reflect_test.XM"},
{TypeOf(new(XM).String), "func() string"}, {TypeOf(new(XM).String), "func() string"},
{TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) 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 { for i, test := range stringTests {
......
...@@ -4,8 +4,69 @@ ...@@ -4,8 +4,69 @@
// Package pprof writes runtime profiling data in the format expected // Package pprof writes runtime profiling data in the format expected
// by the pprof visualization tool. // 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 // For more information about pprof, see
// http://github.com/google/pprof/. // https://github.com/google/pprof/blob/master/doc/pprof.md.
package pprof package pprof
import ( import (
......
// 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")
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment