diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 08:53:52 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-07-19 08:53:52 +0000 |
commit | 00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387 (patch) | |
tree | b988e32ea14a3dc1b4718b1fdfa47bab087ae96c /libgo/go | |
parent | bcf2fc6ee0a7edbe7de4299f28b66527c07bb0a2 (diff) | |
download | gcc-00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387.tar.gz |
libgo: Update to Go 1.3 release.
From-SVN: r212837
Diffstat (limited to 'libgo/go')
422 files changed, 11539 insertions, 4133 deletions
diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go index e8b973c1faf..e363aa793e0 100644 --- a/libgo/go/archive/tar/common.go +++ b/libgo/go/archive/tar/common.go @@ -38,6 +38,7 @@ const ( TypeXGlobalHeader = 'g' // global extended header TypeGNULongName = 'L' // Next file has a long name TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name + TypeGNUSparse = 'S' // sparse file ) // A Header represents a single header in a tar archive. diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go index 7cb6e649c7b..920a9b08f90 100644 --- a/libgo/go/archive/tar/reader.go +++ b/libgo/go/archive/tar/reader.go @@ -29,12 +29,57 @@ const maxNanoSecondIntSize = 9 // The Next method advances to the next file in the archive (including the first), // and then it can be treated as an io.Reader to access the file's data. type Reader struct { - r io.Reader - err error - nb int64 // number of unread bytes for current file entry - pad int64 // amount of padding (ignored) after current file entry + r io.Reader + err error + pad int64 // amount of padding (ignored) after current file entry + curr numBytesReader // reader for current file entry } +// A numBytesReader is an io.Reader with a numBytes method, returning the number +// of bytes remaining in the underlying encoded data. +type numBytesReader interface { + io.Reader + numBytes() int64 +} + +// A regFileReader is a numBytesReader for reading file data from a tar archive. +type regFileReader struct { + r io.Reader // underlying reader + nb int64 // number of unread bytes for current file entry +} + +// A sparseFileReader is a numBytesReader for reading sparse file data from a tar archive. +type sparseFileReader struct { + rfr *regFileReader // reads the sparse-encoded file data + sp []sparseEntry // the sparse map for the file + pos int64 // keeps track of file position + tot int64 // total size of the file +} + +// Keywords for GNU sparse files in a PAX extended header +const ( + paxGNUSparseNumBlocks = "GNU.sparse.numblocks" + paxGNUSparseOffset = "GNU.sparse.offset" + paxGNUSparseNumBytes = "GNU.sparse.numbytes" + paxGNUSparseMap = "GNU.sparse.map" + paxGNUSparseName = "GNU.sparse.name" + paxGNUSparseMajor = "GNU.sparse.major" + paxGNUSparseMinor = "GNU.sparse.minor" + paxGNUSparseSize = "GNU.sparse.size" + paxGNUSparseRealSize = "GNU.sparse.realsize" +) + +// Keywords for old GNU sparse headers +const ( + oldGNUSparseMainHeaderOffset = 386 + oldGNUSparseMainHeaderIsExtendedOffset = 482 + oldGNUSparseMainHeaderNumEntries = 4 + oldGNUSparseExtendedHeaderIsExtendedOffset = 504 + oldGNUSparseExtendedHeaderNumEntries = 21 + oldGNUSparseOffsetSize = 12 + oldGNUSparseNumBytesSize = 12 +) + // NewReader creates a new Reader reading from r. func NewReader(r io.Reader) *Reader { return &Reader{r: r} } @@ -64,6 +109,18 @@ func (tr *Reader) Next() (*Header, error) { tr.skipUnread() hdr = tr.readHeader() mergePAX(hdr, headers) + + // Check for a PAX format sparse file + sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers) + if err != nil { + tr.err = err + return nil, err + } + if sp != nil { + // Current file is a PAX format GNU sparse file. + // Set the current file reader to a sparse file reader. + tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size} + } return hdr, nil case TypeGNULongName: // We have a GNU long name header. Its contents are the real file name. @@ -87,6 +144,67 @@ func (tr *Reader) Next() (*Header, error) { return hdr, tr.err } +// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then +// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to +// be treated as a regular file. +func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) { + var sparseFormat string + + // Check for sparse format indicators + major, majorOk := headers[paxGNUSparseMajor] + minor, minorOk := headers[paxGNUSparseMinor] + sparseName, sparseNameOk := headers[paxGNUSparseName] + _, sparseMapOk := headers[paxGNUSparseMap] + sparseSize, sparseSizeOk := headers[paxGNUSparseSize] + sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize] + + // Identify which, if any, sparse format applies from which PAX headers are set + if majorOk && minorOk { + sparseFormat = major + "." + minor + } else if sparseNameOk && sparseMapOk { + sparseFormat = "0.1" + } else if sparseSizeOk { + sparseFormat = "0.0" + } else { + // Not a PAX format GNU sparse file. + return nil, nil + } + + // Check for unknown sparse format + if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" { + return nil, nil + } + + // Update hdr from GNU sparse PAX headers + if sparseNameOk { + hdr.Name = sparseName + } + if sparseSizeOk { + realSize, err := strconv.ParseInt(sparseSize, 10, 0) + if err != nil { + return nil, ErrHeader + } + hdr.Size = realSize + } else if sparseRealSizeOk { + realSize, err := strconv.ParseInt(sparseRealSize, 10, 0) + if err != nil { + return nil, ErrHeader + } + hdr.Size = realSize + } + + // Set up the sparse map, according to the particular sparse format in use + var sp []sparseEntry + var err error + switch sparseFormat { + case "0.0", "0.1": + sp, err = readGNUSparseMap0x1(headers) + case "1.0": + sp, err = readGNUSparseMap1x0(tr.curr) + } + return sp, err +} + // mergePAX merges well known headers according to PAX standard. // In general headers with the same name as those found // in the header struct overwrite those found in the header @@ -194,6 +312,11 @@ func parsePAX(r io.Reader) (map[string]string, error) { if err != nil { return nil, err } + + // For GNU PAX sparse format 0.0 support. + // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers. + var sparseMap bytes.Buffer + headers := make(map[string]string) // Each record is constructed as // "%d %s=%s\n", length, keyword, value @@ -211,7 +334,7 @@ func parsePAX(r io.Reader) (map[string]string, error) { return nil, ErrHeader } // Extract everything between the decimal and the n -1 on the - // beginning to to eat the ' ', -1 on the end to skip the newline. + // beginning to eat the ' ', -1 on the end to skip the newline. var record []byte record, buf = buf[sp+1:n-1], buf[n:] // The first equals is guaranteed to mark the end of the key. @@ -221,7 +344,21 @@ func parsePAX(r io.Reader) (map[string]string, error) { return nil, ErrHeader } key, value := record[:eq], record[eq+1:] - headers[string(key)] = string(value) + + keyStr := string(key) + if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes { + // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map. + sparseMap.Write(value) + sparseMap.Write([]byte{','}) + } else { + // Normal key. Set the value in the headers map. + headers[keyStr] = string(value) + } + } + if sparseMap.Len() != 0 { + // Add sparse info to headers, chopping off the extra comma + sparseMap.Truncate(sparseMap.Len() - 1) + headers[paxGNUSparseMap] = sparseMap.String() } return headers, nil } @@ -268,8 +405,8 @@ func (tr *Reader) octal(b []byte) int64 { // skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding. func (tr *Reader) skipUnread() { - nr := tr.nb + tr.pad // number of bytes to skip - tr.nb, tr.pad = 0, 0 + nr := tr.numBytes() + tr.pad // number of bytes to skip + tr.curr, tr.pad = nil, 0 if sr, ok := tr.r.(io.Seeker); ok { if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil { return @@ -331,14 +468,14 @@ func (tr *Reader) readHeader() *Header { // so its magic bytes, like the rest of the block, are NULs. magic := string(s.next(8)) // contains version field as well. var format string - switch magic { - case "ustar\x0000": // POSIX tar (1003.1-1988) + switch { + case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988) if string(header[508:512]) == "tar\x00" { format = "star" } else { format = "posix" } - case "ustar \x00": // old GNU tar + case magic == "ustar \x00": // old GNU tar format = "gnu" } @@ -373,30 +510,308 @@ func (tr *Reader) readHeader() *Header { // Maximum value of hdr.Size is 64 GB (12 octal digits), // so there's no risk of int64 overflowing. - tr.nb = int64(hdr.Size) - tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two + nb := int64(hdr.Size) + tr.pad = -nb & (blockSize - 1) // blockSize is a power of two + + // Set the current file reader. + tr.curr = ®FileReader{r: tr.r, nb: nb} + + // Check for old GNU sparse format entry. + if hdr.Typeflag == TypeGNUSparse { + // Get the real size of the file. + hdr.Size = tr.octal(header[483:495]) + + // Read the sparse map. + sp := tr.readOldGNUSparseMap(header) + if tr.err != nil { + return nil + } + // Current file is a GNU sparse file. Update the current file reader. + tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size} + } return hdr } +// A sparseEntry holds a single entry in a sparse file's sparse map. +// A sparse entry indicates the offset and size in a sparse file of a +// block of data. +type sparseEntry struct { + offset int64 + numBytes int64 +} + +// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format. +// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries, +// then one or more extension headers are used to store the rest of the sparse map. +func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry { + isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0 + spCap := oldGNUSparseMainHeaderNumEntries + if isExtended { + spCap += oldGNUSparseExtendedHeaderNumEntries + } + sp := make([]sparseEntry, 0, spCap) + s := slicer(header[oldGNUSparseMainHeaderOffset:]) + + // Read the four entries from the main tar header + for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ { + offset := tr.octal(s.next(oldGNUSparseOffsetSize)) + numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize)) + if tr.err != nil { + tr.err = ErrHeader + return nil + } + if offset == 0 && numBytes == 0 { + break + } + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + + for isExtended { + // There are more entries. Read an extension header and parse its entries. + sparseHeader := make([]byte, blockSize) + if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil { + return nil + } + isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0 + s = slicer(sparseHeader) + for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ { + offset := tr.octal(s.next(oldGNUSparseOffsetSize)) + numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize)) + if tr.err != nil { + tr.err = ErrHeader + return nil + } + if offset == 0 && numBytes == 0 { + break + } + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + } + return sp +} + +// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0. +// The sparse map is stored just before the file data and padded out to the nearest block boundary. +func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) { + buf := make([]byte, 2*blockSize) + sparseHeader := buf[:blockSize] + + // readDecimal is a helper function to read a decimal integer from the sparse map + // while making sure to read from the file in blocks of size blockSize + readDecimal := func() (int64, error) { + // Look for newline + nl := bytes.IndexByte(sparseHeader, '\n') + if nl == -1 { + if len(sparseHeader) >= blockSize { + // This is an error + return 0, ErrHeader + } + oldLen := len(sparseHeader) + newLen := oldLen + blockSize + if cap(sparseHeader) < newLen { + // There's more header, but we need to make room for the next block + copy(buf, sparseHeader) + sparseHeader = buf[:newLen] + } else { + // There's more header, and we can just reslice + sparseHeader = sparseHeader[:newLen] + } + + // Now that sparseHeader is large enough, read next block + if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil { + return 0, err + } + + // Look for a newline in the new data + nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n') + if nl == -1 { + // This is an error + return 0, ErrHeader + } + nl += oldLen // We want the position from the beginning + } + // Now that we've found a newline, read a number + n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0) + if err != nil { + return 0, ErrHeader + } + + // Update sparseHeader to consume this number + sparseHeader = sparseHeader[nl+1:] + return n, nil + } + + // Read the first block + if _, err := io.ReadFull(r, sparseHeader); err != nil { + return nil, err + } + + // The first line contains the number of entries + numEntries, err := readDecimal() + if err != nil { + return nil, err + } + + // Read all the entries + sp := make([]sparseEntry, 0, numEntries) + for i := int64(0); i < numEntries; i++ { + // Read the offset + offset, err := readDecimal() + if err != nil { + return nil, err + } + // Read numBytes + numBytes, err := readDecimal() + if err != nil { + return nil, err + } + + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + + return sp, nil +} + +// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format version 0.1. +// The sparse map is stored in the PAX headers. +func readGNUSparseMap0x1(headers map[string]string) ([]sparseEntry, error) { + // Get number of entries + numEntriesStr, ok := headers[paxGNUSparseNumBlocks] + if !ok { + return nil, ErrHeader + } + numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) + if err != nil { + return nil, ErrHeader + } + + sparseMap := strings.Split(headers[paxGNUSparseMap], ",") + + // There should be two numbers in sparseMap for each entry + if int64(len(sparseMap)) != 2*numEntries { + return nil, ErrHeader + } + + // Loop through the entries in the sparse map + sp := make([]sparseEntry, 0, numEntries) + for i := int64(0); i < numEntries; i++ { + offset, err := strconv.ParseInt(sparseMap[2*i], 10, 0) + if err != nil { + return nil, ErrHeader + } + numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 0) + if err != nil { + return nil, ErrHeader + } + sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes}) + } + + return sp, nil +} + +// numBytes returns the number of bytes left to read in the current file's entry +// in the tar archive, or 0 if there is no current file. +func (tr *Reader) numBytes() int64 { + if tr.curr == nil { + // No current file, so no bytes + return 0 + } + return tr.curr.numBytes() +} + // Read reads from the current entry in the tar archive. // It returns 0, io.EOF when it reaches the end of that entry, // until Next is called to advance to the next entry. func (tr *Reader) Read(b []byte) (n int, err error) { - if tr.nb == 0 { - // file consumed + if tr.curr == nil { return 0, io.EOF } + n, err = tr.curr.Read(b) + if err != nil && err != io.EOF { + tr.err = err + } + return +} - if int64(len(b)) > tr.nb { - b = b[0:tr.nb] +func (rfr *regFileReader) Read(b []byte) (n int, err error) { + if rfr.nb == 0 { + // file consumed + return 0, io.EOF } - n, err = tr.r.Read(b) - tr.nb -= int64(n) + if int64(len(b)) > rfr.nb { + b = b[0:rfr.nb] + } + n, err = rfr.r.Read(b) + rfr.nb -= int64(n) - if err == io.EOF && tr.nb > 0 { + if err == io.EOF && rfr.nb > 0 { err = io.ErrUnexpectedEOF } - tr.err = err return } + +// numBytes returns the number of bytes left to read in the file's data in the tar archive. +func (rfr *regFileReader) numBytes() int64 { + return rfr.nb +} + +// readHole reads a sparse file hole ending at offset toOffset +func (sfr *sparseFileReader) readHole(b []byte, toOffset int64) int { + n64 := toOffset - sfr.pos + if n64 > int64(len(b)) { + n64 = int64(len(b)) + } + n := int(n64) + for i := 0; i < n; i++ { + b[i] = 0 + } + sfr.pos += n64 + return n +} + +// Read reads the sparse file data in expanded form. +func (sfr *sparseFileReader) Read(b []byte) (n int, err error) { + if len(sfr.sp) == 0 { + // No more data fragments to read from. + if sfr.pos < sfr.tot { + // We're in the last hole + n = sfr.readHole(b, sfr.tot) + return + } + // Otherwise, we're at the end of the file + return 0, io.EOF + } + if sfr.pos < sfr.sp[0].offset { + // We're in a hole + n = sfr.readHole(b, sfr.sp[0].offset) + return + } + + // We're not in a hole, so we'll read from the next data fragment + posInFragment := sfr.pos - sfr.sp[0].offset + bytesLeft := sfr.sp[0].numBytes - posInFragment + if int64(len(b)) > bytesLeft { + b = b[0:bytesLeft] + } + + n, err = sfr.rfr.Read(b) + sfr.pos += int64(n) + + if int64(n) == bytesLeft { + // We're done with this fragment + sfr.sp = sfr.sp[1:] + } + + if err == io.EOF && sfr.pos < sfr.tot { + // We reached the end of the last fragment's data, but there's a final hole + err = nil + } + return +} + +// numBytes returns the number of bytes left to read in the sparse file's +// sparse-encoded data in the tar archive. +func (sfr *sparseFileReader) numBytes() int64 { + return sfr.rfr.nb +} diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go index f84dbebe989..9601ffe4597 100644 --- a/libgo/go/archive/tar/reader_test.go +++ b/libgo/go/archive/tar/reader_test.go @@ -9,6 +9,7 @@ import ( "crypto/md5" "fmt" "io" + "io/ioutil" "os" "reflect" "strings" @@ -54,8 +55,92 @@ var gnuTarTest = &untarTest{ }, } +var sparseTarTest = &untarTest{ + file: "testdata/sparse-formats.tar", + headers: []*Header{ + { + Name: "sparse-gnu", + Mode: 420, + Uid: 1000, + Gid: 1000, + Size: 200, + ModTime: time.Unix(1392395740, 0), + Typeflag: 0x53, + Linkname: "", + Uname: "david", + Gname: "david", + Devmajor: 0, + Devminor: 0, + }, + { + Name: "sparse-posix-0.0", + Mode: 420, + Uid: 1000, + Gid: 1000, + Size: 200, + ModTime: time.Unix(1392342187, 0), + Typeflag: 0x30, + Linkname: "", + Uname: "david", + Gname: "david", + Devmajor: 0, + Devminor: 0, + }, + { + Name: "sparse-posix-0.1", + Mode: 420, + Uid: 1000, + Gid: 1000, + Size: 200, + ModTime: time.Unix(1392340456, 0), + Typeflag: 0x30, + Linkname: "", + Uname: "david", + Gname: "david", + Devmajor: 0, + Devminor: 0, + }, + { + Name: "sparse-posix-1.0", + Mode: 420, + Uid: 1000, + Gid: 1000, + Size: 200, + ModTime: time.Unix(1392337404, 0), + Typeflag: 0x30, + Linkname: "", + Uname: "david", + Gname: "david", + Devmajor: 0, + Devminor: 0, + }, + { + Name: "end", + Mode: 420, + Uid: 1000, + Gid: 1000, + Size: 4, + ModTime: time.Unix(1392398319, 0), + Typeflag: 0x30, + Linkname: "", + Uname: "david", + Gname: "david", + Devmajor: 0, + Devminor: 0, + }, + }, + cksums: []string{ + "6f53234398c2449fe67c1812d993012f", + "6f53234398c2449fe67c1812d993012f", + "6f53234398c2449fe67c1812d993012f", + "6f53234398c2449fe67c1812d993012f", + "b0061974914468de549a2af8ced10316", + }, +} + var untarTests = []*untarTest{ gnuTarTest, + sparseTarTest, { file: "testdata/star.tar", headers: []*Header{ @@ -386,7 +471,7 @@ func TestParsePAXHeader(t *testing.T) { func TestParsePAXTime(t *testing.T) { // Some valid PAX time values timestamps := map[string]time.Time{ - "1350244992.023960108": time.Unix(1350244992, 23960108), // The commoon case + "1350244992.023960108": time.Unix(1350244992, 23960108), // The common case "1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value "1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value "1350244992": time.Unix(1350244992, 0), // Low precision value @@ -423,3 +508,236 @@ func TestMergePAX(t *testing.T) { t.Errorf("incorrect merge: got %+v, want %+v", hdr, want) } } + +func TestSparseEndToEnd(t *testing.T) { + test := sparseTarTest + f, err := os.Open(test.file) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer f.Close() + + tr := NewReader(f) + + headers := test.headers + cksums := test.cksums + nread := 0 + + // loop over all files + for ; ; nread++ { + hdr, err := tr.Next() + if hdr == nil || err == io.EOF { + break + } + + // check the header + if !reflect.DeepEqual(*hdr, *headers[nread]) { + t.Errorf("Incorrect header:\nhave %+v\nwant %+v", + *hdr, headers[nread]) + } + + // read and checksum the file data + h := md5.New() + _, err = io.Copy(h, tr) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // verify checksum + have := fmt.Sprintf("%x", h.Sum(nil)) + want := cksums[nread] + if want != have { + t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want) + } + } + if nread != len(headers) { + t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread) + } +} + +type sparseFileReadTest struct { + sparseData []byte + sparseMap []sparseEntry + realSize int64 + expected []byte +} + +var sparseFileReadTests = []sparseFileReadTest{ + { + sparseData: []byte("abcde"), + sparseMap: []sparseEntry{ + {offset: 0, numBytes: 2}, + {offset: 5, numBytes: 3}, + }, + realSize: 8, + expected: []byte("ab\x00\x00\x00cde"), + }, + { + sparseData: []byte("abcde"), + sparseMap: []sparseEntry{ + {offset: 0, numBytes: 2}, + {offset: 5, numBytes: 3}, + }, + realSize: 10, + expected: []byte("ab\x00\x00\x00cde\x00\x00"), + }, + { + sparseData: []byte("abcde"), + sparseMap: []sparseEntry{ + {offset: 1, numBytes: 3}, + {offset: 6, numBytes: 2}, + }, + realSize: 8, + expected: []byte("\x00abc\x00\x00de"), + }, + { + sparseData: []byte("abcde"), + sparseMap: []sparseEntry{ + {offset: 1, numBytes: 3}, + {offset: 6, numBytes: 2}, + }, + realSize: 10, + expected: []byte("\x00abc\x00\x00de\x00\x00"), + }, + { + sparseData: []byte(""), + sparseMap: nil, + realSize: 2, + expected: []byte("\x00\x00"), + }, +} + +func TestSparseFileReader(t *testing.T) { + for i, test := range sparseFileReadTests { + r := bytes.NewReader(test.sparseData) + nb := int64(r.Len()) + sfr := &sparseFileReader{ + rfr: ®FileReader{r: r, nb: nb}, + sp: test.sparseMap, + pos: 0, + tot: test.realSize, + } + if sfr.numBytes() != nb { + t.Errorf("test %d: Before reading, sfr.numBytes() = %d, want %d", i, sfr.numBytes(), nb) + } + buf, err := ioutil.ReadAll(sfr) + if err != nil { + t.Errorf("test %d: Unexpected error: %v", i, err) + } + if e := test.expected; !bytes.Equal(buf, e) { + t.Errorf("test %d: Contents = %v, want %v", i, buf, e) + } + if sfr.numBytes() != 0 { + t.Errorf("test %d: After draining the reader, numBytes() was nonzero", i) + } + } +} + +func TestSparseIncrementalRead(t *testing.T) { + sparseMap := []sparseEntry{{10, 2}} + sparseData := []byte("Go") + expected := "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Go\x00\x00\x00\x00\x00\x00\x00\x00" + + r := bytes.NewReader(sparseData) + nb := int64(r.Len()) + sfr := &sparseFileReader{ + rfr: ®FileReader{r: r, nb: nb}, + sp: sparseMap, + pos: 0, + tot: int64(len(expected)), + } + + // We'll read the data 6 bytes at a time, with a hole of size 10 at + // the beginning and one of size 8 at the end. + var outputBuf bytes.Buffer + buf := make([]byte, 6) + for { + n, err := sfr.Read(buf) + if err == io.EOF { + break + } + if err != nil { + t.Errorf("Read: unexpected error %v\n", err) + } + if n > 0 { + _, err := outputBuf.Write(buf[:n]) + if err != nil { + t.Errorf("Write: unexpected error %v\n", err) + } + } + } + got := outputBuf.String() + if got != expected { + t.Errorf("Contents = %v, want %v", got, expected) + } +} + +func TestReadGNUSparseMap0x1(t *testing.T) { + headers := map[string]string{ + paxGNUSparseNumBlocks: "4", + paxGNUSparseMap: "0,5,10,5,20,5,30,5", + } + expected := []sparseEntry{ + {offset: 0, numBytes: 5}, + {offset: 10, numBytes: 5}, + {offset: 20, numBytes: 5}, + {offset: 30, numBytes: 5}, + } + + sp, err := readGNUSparseMap0x1(headers) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(sp, expected) { + t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected) + } +} + +func TestReadGNUSparseMap1x0(t *testing.T) { + // This test uses lots of holes so the sparse header takes up more than two blocks + numEntries := 100 + expected := make([]sparseEntry, 0, numEntries) + sparseMap := new(bytes.Buffer) + + fmt.Fprintf(sparseMap, "%d\n", numEntries) + for i := 0; i < numEntries; i++ { + offset := int64(2048 * i) + numBytes := int64(1024) + expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes}) + fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes) + } + + // Make the header the smallest multiple of blockSize that fits the sparseMap + headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize + bufLen := blockSize * headerBlocks + buf := make([]byte, bufLen) + copy(buf, sparseMap.Bytes()) + + // Get an reader to read the sparse map + r := bytes.NewReader(buf) + + // Read the sparse map + sp, err := readGNUSparseMap1x0(r) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + if !reflect.DeepEqual(sp, expected) { + t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected) + } +} + +func TestUninitializedRead(t *testing.T) { + test := gnuTarTest + f, err := os.Open(test.file) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + defer f.Close() + + tr := NewReader(f) + _, err = tr.Read([]byte{}) + if err == nil || err != io.EOF { + t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF) + } + +} diff --git a/libgo/go/archive/tar/testdata/sparse-formats.tar b/libgo/go/archive/tar/testdata/sparse-formats.tar Binary files differnew file mode 100644 index 00000000000..8bd4e74d50f --- /dev/null +++ b/libgo/go/archive/tar/testdata/sparse-formats.tar diff --git a/libgo/go/archive/tar/testdata/writer-big-long.tar b/libgo/go/archive/tar/testdata/writer-big-long.tar Binary files differnew file mode 100644 index 00000000000..5960ee82478 --- /dev/null +++ b/libgo/go/archive/tar/testdata/writer-big-long.tar diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go index 9ee94992970..6eff6f6f84d 100644 --- a/libgo/go/archive/tar/writer.go +++ b/libgo/go/archive/tar/writer.go @@ -218,8 +218,8 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error { tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil) // Use the ustar magic if we used ustar long names. - if len(prefix) > 0 { - copy(header[257:265], []byte("ustar\000")) + if len(prefix) > 0 && !tw.usedBinary { + copy(header[257:265], []byte("ustar\x00")) } } } diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go index 2b9ea658db4..512fab1a6f1 100644 --- a/libgo/go/archive/tar/writer_test.go +++ b/libgo/go/archive/tar/writer_test.go @@ -103,6 +103,29 @@ var writerTests = []*writerTest{ }, }, }, + // The truncated test file was produced using these commands: + // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt + // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar + { + file: "testdata/writer-big-long.tar", + entries: []*writerTestEntry{ + { + header: &Header{ + Name: strings.Repeat("longname/", 15) + "16gig.txt", + Mode: 0644, + Uid: 1000, + Gid: 1000, + Size: 16 << 30, + ModTime: time.Unix(1399583047, 0), + Typeflag: '0', + Uname: "guillaume", + Gname: "guillaume", + }, + // fake contents + contents: strings.Repeat("\x00", 4<<10), + }, + }, + }, // This file was produced using gnu tar 1.17 // gnutar -b 4 --format=ustar (longname/)*15 + file.txt { diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go index 65e5238c3b4..cb28e832423 100644 --- a/libgo/go/archive/zip/struct.go +++ b/libgo/go/archive/zip/struct.go @@ -174,13 +174,13 @@ func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) { return } -// ModTime returns the modification time. +// ModTime returns the modification time in UTC. // The resolution is 2s. func (h *FileHeader) ModTime() time.Time { return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) } -// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time. +// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC. // The resolution is 2s. func (h *FileHeader) SetModTime(t time.Time) { h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t) diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go index d1ff3c9edc1..61ef2619100 100644 --- a/libgo/go/bufio/bufio.go +++ b/libgo/go/bufio/bufio.go @@ -38,6 +38,7 @@ type Reader struct { } const minReadBufferSize = 16 +const maxConsecutiveEmptyReads = 100 // NewReaderSize returns a new Reader whose buffer has at least the specified // size. If the argument io.Reader is already a Reader with large enough @@ -87,15 +88,26 @@ func (b *Reader) fill() { b.r = 0 } - // Read new data. - n, err := b.rd.Read(b.buf[b.w:]) - if n < 0 { - panic(errNegativeRead) + if b.w >= len(b.buf) { + panic("bufio: tried to fill full buffer") } - b.w += n - if err != nil { - b.err = err + + // Read new data: try a limited number of times. + for i := maxConsecutiveEmptyReads; i > 0; i-- { + n, err := b.rd.Read(b.buf[b.w:]) + if n < 0 { + panic(errNegativeRead) + } + b.w += n + if err != nil { + b.err = err + return + } + if n > 0 { + return + } } + b.err = io.ErrNoProgress } func (b *Reader) readErr() error { @@ -115,8 +127,9 @@ func (b *Reader) Peek(n int) ([]byte, error) { if n > len(b.buf) { return nil, ErrBufferFull } + // 0 <= n <= len(b.buf) for b.w-b.r < n && b.err == nil { - b.fill() + b.fill() // b.w-b.r < len(b.buf) => buffer is not full } m := b.w - b.r if m > n { @@ -142,7 +155,7 @@ func (b *Reader) Read(p []byte) (n int, err error) { if n == 0 { return 0, b.readErr() } - if b.w == b.r { + if b.r == b.w { if b.err != nil { return 0, b.readErr() } @@ -150,13 +163,16 @@ func (b *Reader) Read(p []byte) (n int, err error) { // Large read, empty buffer. // Read directly into p to avoid copy. n, b.err = b.rd.Read(p) + if n < 0 { + panic(errNegativeRead) + } if n > 0 { b.lastByte = int(p[n-1]) b.lastRuneSize = -1 } return n, b.readErr() } - b.fill() + b.fill() // buffer is empty if b.w == b.r { return 0, b.readErr() } @@ -176,11 +192,11 @@ func (b *Reader) Read(p []byte) (n int, err error) { // If no byte is available, returns an error. func (b *Reader) ReadByte() (c byte, err error) { b.lastRuneSize = -1 - for b.w == b.r { + for b.r == b.w { if b.err != nil { return 0, b.readErr() } - b.fill() + b.fill() // buffer is empty } c = b.buf[b.r] b.r++ @@ -190,19 +206,19 @@ func (b *Reader) ReadByte() (c byte, err error) { // UnreadByte unreads the last byte. Only the most recently read byte can be unread. func (b *Reader) UnreadByte() error { - b.lastRuneSize = -1 - if b.r == b.w && b.lastByte >= 0 { - b.w = 1 - b.r = 0 - b.buf[0] = byte(b.lastByte) - b.lastByte = -1 - return nil - } - if b.r <= 0 { + if b.lastByte < 0 || b.r == 0 && b.w > 0 { return ErrInvalidUnreadByte } - b.r-- + // b.r > 0 || b.w == 0 + if b.r > 0 { + b.r-- + } else { + // b.r == 0 && b.w == 0 + b.w = 1 + } + b.buf[b.r] = byte(b.lastByte) b.lastByte = -1 + b.lastRuneSize = -1 return nil } @@ -210,8 +226,8 @@ func (b *Reader) UnreadByte() error { // rune and its size in bytes. If the encoded rune is invalid, it consumes one byte // and returns unicode.ReplacementChar (U+FFFD) with a size of 1. func (b *Reader) ReadRune() (r rune, size int, err error) { - for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil { - b.fill() + for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil && b.w-b.r < len(b.buf) { + b.fill() // b.w-b.r < len(buf) => buffer is not full } b.lastRuneSize = -1 if b.r == b.w { @@ -232,7 +248,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) { // regard it is stricter than UnreadByte, which will unread the last byte // from any read operation.) func (b *Reader) UnreadRune() error { - if b.lastRuneSize < 0 || b.r == 0 { + if b.lastRuneSize < 0 || b.r < b.lastRuneSize { return ErrInvalidUnreadRune } b.r -= b.lastRuneSize @@ -255,37 +271,39 @@ func (b *Reader) Buffered() int { return b.w - b.r } // ReadBytes or ReadString instead. // ReadSlice returns err != nil if and only if line does not end in delim. func (b *Reader) ReadSlice(delim byte) (line []byte, err error) { - // Look in buffer. - if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 { - line1 := b.buf[b.r : b.r+i+1] - b.r += i + 1 - return line1, nil - } - - // Read more into buffer, until buffer fills or we find delim. for { - if b.err != nil { - line := b.buf[b.r:b.w] - b.r = b.w - return line, b.readErr() + // Search buffer. + if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 { + line = b.buf[b.r : b.r+i+1] + b.r += i + 1 + break } - n := b.Buffered() - b.fill() - - // Search new part of buffer - if i := bytes.IndexByte(b.buf[n:b.w], delim); i >= 0 { - line := b.buf[0 : n+i+1] - b.r = n + i + 1 - return line, nil + // Pending error? + if b.err != nil { + line = b.buf[b.r:b.w] + b.r = b.w + err = b.readErr() + break } - // Buffer is full? - if b.Buffered() >= len(b.buf) { + // Buffer full? + if n := b.Buffered(); n >= len(b.buf) { b.r = b.w - return b.buf, ErrBufferFull + line = b.buf + err = ErrBufferFull + break } + + b.fill() // buffer is not full } + + // Handle last byte, if any. + if i := len(line) - 1; i >= 0 { + b.lastByte = int(line[i]) + } + + return } // ReadLine is a low-level line-reading primitive. Most callers should use @@ -301,6 +319,9 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) { // // The text returned from ReadLine does not include the line end ("\r\n" or "\n"). // No indication or error is given if the input ends without a final line end. +// Calling UnreadByte after ReadLine will always unread the last byte read +// (possibly a character belonging to the line end) even if that byte is not +// part of the line returned by ReadLine. func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) { line, err = b.ReadSlice('\n') if err == ErrBufferFull { @@ -410,12 +431,24 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) { return n, err } - for b.fill(); b.r < b.w; b.fill() { + if w, ok := w.(io.ReaderFrom); ok { + m, err := w.ReadFrom(b.rd) + n += m + return n, err + } + + if b.w-b.r < len(b.buf) { + b.fill() // buffer not full + } + + for b.r < b.w { + // b.r < b.w => buffer is not empty m, err := b.writeBuf(w) n += m if err != nil { return n, err } + b.fill() // buffer is empty } if b.err == io.EOF { @@ -428,6 +461,9 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) { // writeBuf writes the Reader's buffer to the writer. func (b *Reader) writeBuf(w io.Writer) (int64, error) { n, err := w.Write(b.buf[b.r:b.w]) + if n < b.r-b.w { + panic(errors.New("bufio: writer did not write all data")) + } b.r += n return int64(n), err } @@ -619,9 +655,16 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) { return n, err1 } } - m, err = r.Read(b.buf[b.n:]) - if m == 0 { - break + nr := 0 + for nr < maxConsecutiveEmptyReads { + m, err = r.Read(b.buf[b.n:]) + if m != 0 || err != nil { + break + } + nr++ + } + if nr == maxConsecutiveEmptyReads { + return n, io.ErrNoProgress } b.n += m n += int64(m) diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go index 3c86857e107..76d3c8eade8 100644 --- a/libgo/go/bufio/bufio_test.go +++ b/libgo/go/bufio/bufio_test.go @@ -14,6 +14,7 @@ import ( "strings" "testing" "testing/iotest" + "time" "unicode/utf8" ) @@ -174,6 +175,34 @@ func TestReader(t *testing.T) { } } +type zeroReader struct{} + +func (zeroReader) Read(p []byte) (int, error) { + return 0, nil +} + +func TestZeroReader(t *testing.T) { + var z zeroReader + r := NewReader(z) + + c := make(chan error) + go func() { + _, err := r.ReadByte() + c <- err + }() + + select { + case err := <-c: + if err == nil { + t.Error("error expected") + } else if err != io.ErrNoProgress { + t.Error("unexpected error:", err) + } + case <-time.After(time.Second): + t.Error("test timed out (endless loop in ReadByte?)") + } +} + // A StringReader delivers its data one string segment at a time via Read. type StringReader struct { data []string @@ -228,66 +257,150 @@ func TestReadRune(t *testing.T) { } func TestUnreadRune(t *testing.T) { - got := "" segments := []string{"Hello, world:", "日本語"} - data := strings.Join(segments, "") r := NewReader(&StringReader{data: segments}) + got := "" + want := strings.Join(segments, "") // Normal execution. for { r1, _, err := r.ReadRune() if err != nil { if err != io.EOF { - t.Error("unexpected EOF") + t.Error("unexpected error on ReadRune:", err) } break } got += string(r1) - // Put it back and read it again + // Put it back and read it again. if err = r.UnreadRune(); err != nil { - t.Error("unexpected error on UnreadRune:", err) + t.Fatal("unexpected error on UnreadRune:", err) } r2, _, err := r.ReadRune() if err != nil { - t.Error("unexpected error reading after unreading:", err) + t.Fatal("unexpected error reading after unreading:", err) } if r1 != r2 { - t.Errorf("incorrect rune after unread: got %c wanted %c", r1, r2) + t.Fatalf("incorrect rune after unread: got %c, want %c", r1, r2) } } - if got != data { - t.Errorf("want=%q got=%q", data, got) + if got != want { + t.Errorf("got %q, want %q", got, want) } } func TestUnreadByte(t *testing.T) { - want := "Hello, world" - got := "" segments := []string{"Hello, ", "world"} r := NewReader(&StringReader{data: segments}) + got := "" + want := strings.Join(segments, "") // Normal execution. for { b1, err := r.ReadByte() if err != nil { if err != io.EOF { - t.Fatal("unexpected EOF") + t.Error("unexpected error on ReadByte:", err) } break } got += string(b1) - // Put it back and read it again + // Put it back and read it again. if err = r.UnreadByte(); err != nil { - t.Fatalf("unexpected error on UnreadByte: %v", err) + t.Fatal("unexpected error on UnreadByte:", err) } b2, err := r.ReadByte() if err != nil { - t.Fatalf("unexpected error reading after unreading: %v", err) + t.Fatal("unexpected error reading after unreading:", err) } if b1 != b2 { - t.Fatalf("incorrect byte after unread: got %c wanted %c", b1, b2) + t.Fatalf("incorrect byte after unread: got %q, want %q", b1, b2) } } if got != want { - t.Errorf("got=%q want=%q", got, want) + t.Errorf("got %q, want %q", got, want) + } +} + +func TestUnreadByteMultiple(t *testing.T) { + segments := []string{"Hello, ", "world"} + data := strings.Join(segments, "") + for n := 0; n <= len(data); n++ { + r := NewReader(&StringReader{data: segments}) + // Read n bytes. + for i := 0; i < n; i++ { + b, err := r.ReadByte() + if err != nil { + t.Fatalf("n = %d: unexpected error on ReadByte: %v", n, err) + } + if b != data[i] { + t.Fatalf("n = %d: incorrect byte returned from ReadByte: got %q, want %q", n, b, data[i]) + } + } + // Unread one byte if there is one. + if n > 0 { + if err := r.UnreadByte(); err != nil { + t.Errorf("n = %d: unexpected error on UnreadByte: %v", n, err) + } + } + // Test that we cannot unread any further. + if err := r.UnreadByte(); err == nil { + t.Errorf("n = %d: expected error on UnreadByte", n) + } + } +} + +func TestUnreadByteOthers(t *testing.T) { + // A list of readers to use in conjunction with UnreadByte. + var readers = []func(*Reader, byte) ([]byte, error){ + (*Reader).ReadBytes, + (*Reader).ReadSlice, + func(r *Reader, delim byte) ([]byte, error) { + data, err := r.ReadString(delim) + return []byte(data), err + }, + // ReadLine doesn't fit the data/pattern easily + // so we leave it out. It should be covered via + // the ReadSlice test since ReadLine simply calls + // ReadSlice, and it's that function that handles + // the last byte. + } + + // Try all readers with UnreadByte. + for rno, read := range readers { + // Some input data that is longer than the minimum reader buffer size. + const n = 10 + var buf bytes.Buffer + for i := 0; i < n; i++ { + buf.WriteString("abcdefg") + } + + r := NewReaderSize(&buf, minReadBufferSize) + readTo := func(delim byte, want string) { + data, err := read(r, delim) + if err != nil { + t.Fatalf("#%d: unexpected error reading to %c: %v", rno, delim, err) + } + if got := string(data); got != want { + t.Fatalf("#%d: got %q, want %q", rno, got, want) + } + } + + // Read the data with occasional UnreadByte calls. + for i := 0; i < n; i++ { + readTo('d', "abcd") + for j := 0; j < 3; j++ { + if err := r.UnreadByte(); err != nil { + t.Fatalf("#%d: unexpected error on UnreadByte: %v", rno, err) + } + readTo('d', "d") + } + readTo('g', "efg") + } + + // All data should have been read. + _, err := r.ReadByte() + if err != io.EOF { + t.Errorf("#%d: got error %v; want EOF", rno, err) + } } } @@ -1056,7 +1169,61 @@ func TestWriterReadFromWhileFull(t *testing.T) { // Use ReadFrom to read in some data. n2, err := w.ReadFrom(strings.NewReader("abcdef")) if n2 != 6 || err != nil { - t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n, err) + t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n2, err) + } +} + +type emptyThenNonEmptyReader struct { + r io.Reader + n int +} + +func (r *emptyThenNonEmptyReader) Read(p []byte) (int, error) { + if r.n <= 0 { + return r.r.Read(p) + } + r.n-- + return 0, nil +} + +// Test for golang.org/issue/7611 +func TestWriterReadFromUntilEOF(t *testing.T) { + buf := new(bytes.Buffer) + w := NewWriterSize(buf, 5) + + // Partially fill buffer + n, err := w.Write([]byte("0123")) + if n != 4 || err != nil { + t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err) + } + + // Use ReadFrom to read in some data. + r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 3} + n2, err := w.ReadFrom(r) + if n2 != 4 || err != nil { + t.Fatalf("ReadFrom returned (%v, %v), want (4, nil)", n2, err) + } + w.Flush() + if got, want := string(buf.Bytes()), "0123abcd"; got != want { + t.Fatalf("buf.Bytes() returned %q, want %q", got, want) + } +} + +func TestWriterReadFromErrNoProgress(t *testing.T) { + buf := new(bytes.Buffer) + w := NewWriterSize(buf, 5) + + // Partially fill buffer + n, err := w.Write([]byte("0123")) + if n != 4 || err != nil { + t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err) + } + + // Use ReadFrom to read in some data. + r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 100} + n2, err := w.ReadFrom(r) + if n2 != 0 || err != io.ErrNoProgress { + t.Fatalf("buf.Bytes() returned (%v, %v), want (0, io.ErrNoProgress)", n2, err) } } @@ -1094,20 +1261,12 @@ func TestWriterReset(t *testing.T) { // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have. type onlyReader struct { - r io.Reader -} - -func (r onlyReader) Read(b []byte) (int, error) { - return r.r.Read(b) + io.Reader } // An onlyWriter only implements io.Writer, no matter what other methods the underlying implementation may have. type onlyWriter struct { - w io.Writer -} - -func (w onlyWriter) Write(b []byte) (int, error) { - return w.w.Write(b) + io.Writer } func BenchmarkReaderCopyOptimal(b *testing.B) { @@ -1152,6 +1311,27 @@ func BenchmarkReaderCopyNoWriteTo(b *testing.B) { } } +func BenchmarkReaderWriteToOptimal(b *testing.B) { + const bufSize = 16 << 10 + buf := make([]byte, bufSize) + r := bytes.NewReader(buf) + srcReader := NewReaderSize(onlyReader{r}, 1<<10) + if _, ok := ioutil.Discard.(io.ReaderFrom); !ok { + b.Fatal("ioutil.Discard doesn't support ReaderFrom") + } + for i := 0; i < b.N; i++ { + r.Seek(0, 0) + srcReader.Reset(onlyReader{r}) + n, err := srcReader.WriteTo(ioutil.Discard) + if err != nil { + b.Fatal(err) + } + if n != bufSize { + b.Fatalf("n = %d; want %d", n, bufSize) + } + } +} + func BenchmarkWriterCopyOptimal(b *testing.B) { // Optimal case is where the underlying writer implements io.ReaderFrom srcBuf := bytes.NewBuffer(make([]byte, 8192)) diff --git a/libgo/go/bufio/scan.go b/libgo/go/bufio/scan.go index 77b2c2ac6f8..715ce071e3b 100644 --- a/libgo/go/bufio/scan.go +++ b/libgo/go/bufio/scan.go @@ -135,7 +135,7 @@ func (s *Scanner) Scan() bool { } // Must read more data. // First, shift data to beginning of buffer if there's lots of empty space - // or space is neded. + // or space is needed. if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) { copy(s.buf, s.buf[s.start:s.end]) s.end -= s.start @@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool { break } loop++ - if loop > 100 { + if loop > maxConsecutiveEmptyReads { s.setErr(io.ErrNoProgress) break } diff --git a/libgo/go/bufio/scan_test.go b/libgo/go/bufio/scan_test.go index 4ac529fd6dd..0db7cad2047 100644 --- a/libgo/go/bufio/scan_test.go +++ b/libgo/go/bufio/scan_test.go @@ -277,7 +277,7 @@ func TestScanLineNoNewline(t *testing.T) { testNoNewline(text, lines, t) } -// Test that the line splitter handles a final line with a carriage return but nonewline. +// Test that the line splitter handles a final line with a carriage return but no newline. func TestScanLineReturnButNoNewline(t *testing.T) { const text = "abcdefghijklmn\nopqrstuvwxyz\r" lines := []string{ diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go index 644bf75b894..0c53e4c0b71 100644 --- a/libgo/go/bytes/bytes.go +++ b/libgo/go/bytes/bytes.go @@ -356,7 +356,11 @@ func Map(mapping func(r rune) rune, s []byte) []byte { } r = mapping(r) if r >= 0 { - if nbytes+utf8.RuneLen(r) > maxbytes { + rl := utf8.RuneLen(r) + if rl < 0 { + rl = len(string(utf8.RuneError)) + } + if nbytes+rl > maxbytes { // Grow the buffer. maxbytes = maxbytes*2 + utf8.UTFMax nb := make([]byte, maxbytes) diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go index 808655a4a48..394dd7a443d 100644 --- a/libgo/go/bytes/bytes_test.go +++ b/libgo/go/bytes/bytes_test.go @@ -785,6 +785,16 @@ func TestMap(t *testing.T) { if string(m) != expect { t.Errorf("drop: expected %q got %q", expect, m) } + + // 6. Invalid rune + invalidRune := func(r rune) rune { + return utf8.MaxRune + 1 + } + m = Map(invalidRune, []byte("x")) + expect = "\uFFFD" + if string(m) != expect { + t.Errorf("invalidRune: expected %q got %q", expect, m) + } } func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) } @@ -1134,7 +1144,7 @@ func TestEqualFold(t *testing.T) { func TestBufferGrowNegative(t *testing.T) { defer func() { if err := recover(); err == nil { - t.Fatal("Grow(-1) should have paniced") + t.Fatal("Grow(-1) should have panicked") } }() var b Buffer @@ -1144,7 +1154,7 @@ func TestBufferGrowNegative(t *testing.T) { func TestBufferTruncateNegative(t *testing.T) { defer func() { if err := recover(); err == nil { - t.Fatal("Truncate(-1) should have paniced") + t.Fatal("Truncate(-1) should have panicked") } }() var b Buffer @@ -1154,7 +1164,7 @@ func TestBufferTruncateNegative(t *testing.T) { func TestBufferTruncateOutOfRange(t *testing.T) { defer func() { if err := recover(); err == nil { - t.Fatal("Truncate(20) should have paniced") + t.Fatal("Truncate(20) should have panicked") } }() var b Buffer diff --git a/libgo/go/bytes/reader.go b/libgo/go/bytes/reader.go index 77511b94555..d2d40fa7ca1 100644 --- a/libgo/go/bytes/reader.go +++ b/libgo/go/bytes/reader.go @@ -16,40 +16,41 @@ import ( // Unlike a Buffer, a Reader is read-only and supports seeking. type Reader struct { s []byte - i int // current reading index - prevRune int // index of previous rune; or < 0 + i int64 // current reading index + prevRune int // index of previous rune; or < 0 } // Len returns the number of bytes of the unread portion of the // slice. func (r *Reader) Len() int { - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { return 0 } - return len(r.s) - r.i + return int(int64(len(r.s)) - r.i) } func (r *Reader) Read(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil } - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { return 0, io.EOF } - n = copy(b, r.s[r.i:]) - r.i += n r.prevRune = -1 + n = copy(b, r.s[r.i:]) + r.i += int64(n) return } func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { + // cannot modify state - see io.ReaderAt if off < 0 { - return 0, errors.New("bytes: invalid offset") + return 0, errors.New("bytes.Reader.ReadAt: negative offset") } if off >= int64(len(r.s)) { return 0, io.EOF } - n = copy(b, r.s[int(off):]) + n = copy(b, r.s[off:]) if n < len(b) { err = io.EOF } @@ -57,49 +58,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { } func (r *Reader) ReadByte() (b byte, err error) { - if r.i >= len(r.s) { + r.prevRune = -1 + if r.i >= int64(len(r.s)) { return 0, io.EOF } b = r.s[r.i] r.i++ - r.prevRune = -1 return } func (r *Reader) UnreadByte() error { + r.prevRune = -1 if r.i <= 0 { - return errors.New("bytes.Reader: at beginning of slice") + return errors.New("bytes.Reader.UnreadByte: at beginning of slice") } r.i-- - r.prevRune = -1 return nil } func (r *Reader) ReadRune() (ch rune, size int, err error) { - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { + r.prevRune = -1 return 0, 0, io.EOF } - r.prevRune = r.i + r.prevRune = int(r.i) if c := r.s[r.i]; c < utf8.RuneSelf { r.i++ return rune(c), 1, nil } ch, size = utf8.DecodeRune(r.s[r.i:]) - r.i += size + r.i += int64(size) return } func (r *Reader) UnreadRune() error { if r.prevRune < 0 { - return errors.New("bytes.Reader: previous operation was not ReadRune") + return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune") } - r.i = r.prevRune + r.i = int64(r.prevRune) r.prevRune = -1 return nil } // Seek implements the io.Seeker interface. func (r *Reader) Seek(offset int64, whence int) (int64, error) { + r.prevRune = -1 var abs int64 switch whence { case 0: @@ -109,22 +112,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) { case 2: abs = int64(len(r.s)) + offset default: - return 0, errors.New("bytes: invalid whence") + return 0, errors.New("bytes.Reader.Seek: invalid whence") } if abs < 0 { - return 0, errors.New("bytes: negative position") - } - if abs >= 1<<31 { - return 0, errors.New("bytes: position out of range") + return 0, errors.New("bytes.Reader.Seek: negative position") } - r.i = int(abs) + r.i = abs return abs, nil } // WriteTo implements the io.WriterTo interface. func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { r.prevRune = -1 - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { return 0, nil } b := r.s[r.i:] @@ -132,7 +132,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { if m > len(b) { panic("bytes.Reader.WriteTo: invalid Write count") } - r.i += m + r.i += int64(m) n = int64(m) if m != len(b) && err == nil { err = io.ErrShortWrite diff --git a/libgo/go/bytes/reader_test.go b/libgo/go/bytes/reader_test.go index 19f014da030..d3dce53499e 100644 --- a/libgo/go/bytes/reader_test.go +++ b/libgo/go/bytes/reader_test.go @@ -10,6 +10,7 @@ import ( "io" "io/ioutil" "os" + "sync" "testing" ) @@ -26,9 +27,9 @@ func TestReader(t *testing.T) { {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"}, {seek: os.SEEK_SET, off: 1, n: 1, want: "1"}, {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"}, - {seek: os.SEEK_SET, off: -1, seekerr: "bytes: negative position"}, - {seek: os.SEEK_SET, off: 1<<31 - 1}, - {seek: os.SEEK_CUR, off: 1, seekerr: "bytes: position out of range"}, + {seek: os.SEEK_SET, off: -1, seekerr: "bytes.Reader.Seek: negative position"}, + {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33}, + {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1}, {seek: os.SEEK_SET, n: 5, want: "01234"}, {seek: os.SEEK_CUR, n: 5, want: "56789"}, {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"}, @@ -60,6 +61,16 @@ func TestReader(t *testing.T) { } } +func TestReadAfterBigSeek(t *testing.T) { + r := NewReader([]byte("0123456789")) + if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil { + t.Fatal(err) + } + if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF { + t.Errorf("Read = %d, %v; want 0, EOF", n, err) + } +} + func TestReaderAt(t *testing.T) { r := NewReader([]byte("0123456789")) tests := []struct { @@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) { {1, 9, "123456789", nil}, {11, 10, "", io.EOF}, {0, 0, "", nil}, - {-1, 0, "", "bytes: invalid offset"}, + {-1, 0, "", "bytes.Reader.ReadAt: negative offset"}, } for i, tt := range tests { b := make([]byte, tt.n) @@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) { } } +func TestReaderAtConcurrent(t *testing.T) { + // Test for the race detector, to verify ReadAt doesn't mutate + // any state. + r := NewReader([]byte("0123456789")) + var wg sync.WaitGroup + for i := 0; i < 5; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + var buf [1]byte + r.ReadAt(buf[:], int64(i)) + }(i) + } + wg.Wait() +} + +func TestEmptyReaderConcurrent(t *testing.T) { + // Test for the race detector, to verify a Read that doesn't yield any bytes + // is okay to use from multiple goroutines. This was our historic behavior. + // See golang.org/issue/7856 + r := NewReader([]byte{}) + var wg sync.WaitGroup + for i := 0; i < 5; i++ { + wg.Add(2) + go func() { + defer wg.Done() + var buf [1]byte + r.Read(buf[:]) + }() + go func() { + defer wg.Done() + r.Read(nil) + }() + } + wg.Wait() +} + func TestReaderWriteTo(t *testing.T) { for i := 0; i < 30; i += 3 { var l int @@ -133,6 +181,32 @@ func TestReaderLen(t *testing.T) { } } +var UnreadRuneErrorTests = []struct { + name string + f func(*Reader) +}{ + {"Read", func(r *Reader) { r.Read([]byte{0}) }}, + {"ReadByte", func(r *Reader) { r.ReadByte() }}, + {"UnreadRune", func(r *Reader) { r.UnreadRune() }}, + {"Seek", func(r *Reader) { r.Seek(0, 1) }}, + {"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }}, +} + +func TestUnreadRuneError(t *testing.T) { + for _, tt := range UnreadRuneErrorTests { + reader := NewReader([]byte("0123456789")) + if _, _, err := reader.ReadRune(); err != nil { + // should not happen + t.Fatal(err) + } + tt.f(reader) + err := reader.UnreadRune() + if err == nil { + t.Errorf("Unreading after %s: expected error", tt.name) + } + } +} + func TestReaderDoubleUnreadRune(t *testing.T) { buf := NewBuffer([]byte("groucho")) if _, _, err := buf.ReadRune(); err != nil { diff --git a/libgo/go/compress/bzip2/bzip2_test.go b/libgo/go/compress/bzip2/bzip2_test.go index cd647e5ae00..727249dc462 100644 --- a/libgo/go/compress/bzip2/bzip2_test.go +++ b/libgo/go/compress/bzip2/bzip2_test.go @@ -177,7 +177,7 @@ const ( var testfiles = []string{ // Digits is the digits of the irrational number e. Its decimal representation - // does not repeat, but there are only 10 posible digits, so it should be + // does not repeat, but there are only 10 possible digits, so it should be // reasonably compressible. digits: "testdata/e.txt.bz2", // Twain is Project Gutenberg's edition of Mark Twain's classic English novel. diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go index bbe4c5a16fb..ce4923eca37 100644 --- a/libgo/go/compress/flate/inflate.go +++ b/libgo/go/compress/flate/inflate.go @@ -54,7 +54,7 @@ func (e *WriteError) Error() string { return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() } -// Note that much of the implemenation of huffmanDecoder is also copied +// Note that much of the implementation of huffmanDecoder is also copied // into gen.go (in package main) for the purpose of precomputing the // fixed huffman tables so they can be included statically. diff --git a/libgo/go/compress/flate/reader_test.go b/libgo/go/compress/flate/reader_test.go index 2a8ebbc9438..a62ef741df3 100644 --- a/libgo/go/compress/flate/reader_test.go +++ b/libgo/go/compress/flate/reader_test.go @@ -29,7 +29,7 @@ const ( var testfiles = []string{ // Digits is the digits of the irrational number e. Its decimal representation - // does not repeat, but there are only 10 posible digits, so it should be + // does not repeat, but there are only 10 possible digits, so it should be // reasonably compressible. digits: "../testdata/e.txt", // Twain is Project Gutenberg's edition of Mark Twain's classic English novel. diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go index 1fb9b0964ce..4f398b194a0 100644 --- a/libgo/go/compress/gzip/gunzip.go +++ b/libgo/go/compress/gzip/gunzip.go @@ -89,6 +89,21 @@ func NewReader(r io.Reader) (*Reader, error) { return z, nil } +// Reset discards the Reader z's state and makes it equivalent to the +// result of its original state from NewReader, but reading from r instead. +// This permits reusing a Reader rather than allocating a new one. +func (z *Reader) Reset(r io.Reader) error { + z.r = makeReader(r) + if z.digest == nil { + z.digest = crc32.NewIEEE() + } else { + z.digest.Reset() + } + z.size = 0 + z.err = nil + return z.readHeader(true) +} + // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). func get4(p []byte) uint32 { return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 diff --git a/libgo/go/compress/gzip/gunzip_test.go b/libgo/go/compress/gzip/gunzip_test.go index 56153737377..2471038f536 100644 --- a/libgo/go/compress/gzip/gunzip_test.go +++ b/libgo/go/compress/gzip/gunzip_test.go @@ -303,6 +303,26 @@ func TestDecompressor(t *testing.T) { if s != tt.raw { t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw) } + + // Test Reader Reset. + in = bytes.NewReader(tt.gzip) + err = gzip.Reset(in) + if err != nil { + t.Errorf("%s: Reset: %s", tt.name, err) + continue + } + if tt.name != gzip.Name { + t.Errorf("%s: got name %s", tt.name, gzip.Name) + } + b.Reset() + n, err = io.Copy(b, gzip) + if err != tt.err { + t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err) + } + s = b.String() + if s != tt.raw { + t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw) + } } } @@ -333,3 +353,17 @@ func TestIssue6550(t *testing.T) { // ok } } + +func TestInitialReset(t *testing.T) { + var r Reader + if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil { + t.Error(err) + } + var buf bytes.Buffer + if _, err := io.Copy(&buf, &r); err != nil { + t.Error(err) + } + if s := buf.String(); s != gunzipTests[1].raw { + t.Errorf("got %q want %q", s, gunzipTests[1].raw) + } +} diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go index fe32d6871ae..3a0bf54e1b9 100644 --- a/libgo/go/compress/gzip/gzip.go +++ b/libgo/go/compress/gzip/gzip.go @@ -22,8 +22,8 @@ const ( DefaultCompression = flate.DefaultCompression ) -// A Writer is an io.WriteCloser that satisfies writes by compressing data written -// to its wrapped io.Writer. +// A Writer is an io.WriteCloser. +// Writes to a Writer are compressed and written to w. type Writer struct { Header w io.Writer @@ -37,8 +37,8 @@ type Writer struct { err error } -// NewWriter creates a new Writer that satisfies writes by compressing data -// written to w. +// NewWriter returns a new Writer. +// Writes to the returned writer are compressed and written to w. // // It is the caller's responsibility to call Close on the WriteCloser when done. // Writes may be buffered and not flushed until Close. diff --git a/libgo/go/compress/lzw/reader.go b/libgo/go/compress/lzw/reader.go index efbc758f94b..ef596991032 100644 --- a/libgo/go/compress/lzw/reader.go +++ b/libgo/go/compress/lzw/reader.go @@ -216,8 +216,8 @@ func (d *decoder) Close() error { return nil } -// NewReader creates a new io.ReadCloser that satisfies reads by decompressing -// the data read from r. +// NewReader creates a new io.ReadCloser. +// Reads from the returned io.ReadCloser read and decompress data from r. // It is the caller's responsibility to call Close on the ReadCloser when // finished reading. // The number of bits to use for literal codes, litWidth, must be in the diff --git a/libgo/go/compress/lzw/writer.go b/libgo/go/compress/lzw/writer.go index b20691864b5..961b25f94f5 100644 --- a/libgo/go/compress/lzw/writer.go +++ b/libgo/go/compress/lzw/writer.go @@ -225,8 +225,8 @@ func (e *encoder) Close() error { return e.w.Flush() } -// NewWriter creates a new io.WriteCloser that satisfies writes by compressing -// the data and writing it to w. +// NewWriter creates a new io.WriteCloser. +// Writes to the returned io.WriteCloser are compressed and written to w. // It is the caller's responsibility to call Close on the WriteCloser when // finished writing. // The number of bits to use for literal codes, litWidth, must be in the diff --git a/libgo/go/compress/zlib/reader.go b/libgo/go/compress/zlib/reader.go index d54746f4c02..9e1aafda9b6 100644 --- a/libgo/go/compress/zlib/reader.go +++ b/libgo/go/compress/zlib/reader.go @@ -51,7 +51,8 @@ type reader struct { scratch [4]byte } -// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r. +// NewReader creates a new io.ReadCloser. +// Reads from the returned io.ReadCloser read and decompress data from r. // The implementation buffers input and may read more data than necessary from r. // It is the caller's responsibility to call Close on the ReadCloser when done. func NewReader(r io.Reader) (io.ReadCloser, error) { diff --git a/libgo/go/compress/zlib/writer.go b/libgo/go/compress/zlib/writer.go index 99ff6549acb..fac7e15a7e3 100644 --- a/libgo/go/compress/zlib/writer.go +++ b/libgo/go/compress/zlib/writer.go @@ -34,8 +34,8 @@ type Writer struct { wroteHeader bool } -// NewWriter creates a new Writer that satisfies writes by compressing data -// written to w. +// NewWriter creates a new Writer. +// Writes to the returned Writer are compressed and written to w. // // It is the caller's responsibility to call Close on the WriteCloser when done. // Writes may be buffered and not flushed until Close. diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go index cf9c8325455..71ba81aaa76 100644 --- a/libgo/go/compress/zlib/writer_test.go +++ b/libgo/go/compress/zlib/writer_test.go @@ -120,7 +120,7 @@ func testFileLevelDictReset(t *testing.T, fn string, level int, dict []byte) { } out := buf.String() - // Reset and comprses again. + // Reset and compress again. buf2 := new(bytes.Buffer) zlibw.Reset(buf2) _, err = zlibw.Write(b0) diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go index 3fe2327ad2d..c467a11910c 100644 --- a/libgo/go/container/heap/heap.go +++ b/libgo/go/container/heap/heap.go @@ -78,7 +78,7 @@ func Remove(h Interface, i int) interface{} { return h.Pop() } -// Fix reestablishes the heap ordering after the element at index i has changed its value. +// Fix re-establishes the heap ordering after the element at index i has changed its value. // Changing the value of the element at index i and then calling Fix is equivalent to, // but less expensive than, calling Remove(h, i) followed by a Push of the new value. // The complexity is O(log(n)) where n = h.Len(). diff --git a/libgo/go/crypto/aes/aes_test.go b/libgo/go/crypto/aes/aes_test.go index 6261dd09fb5..363180931c7 100644 --- a/libgo/go/crypto/aes/aes_test.go +++ b/libgo/go/crypto/aes/aes_test.go @@ -354,6 +354,34 @@ func TestCipherDecrypt(t *testing.T) { } } +// Test short input/output. +// Assembly used to not notice. +// See issue 7928. +func TestShortBlocks(t *testing.T) { + bytes := func(n int) []byte { return make([]byte, n) } + + c, _ := NewCipher(bytes(16)) + + mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(1), bytes(1)) }) + mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(1), bytes(1)) }) + mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(100), bytes(1)) }) + mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(100), bytes(1)) }) + mustPanic(t, "crypto/aes: output not full block", func() { c.Encrypt(bytes(1), bytes(100)) }) + mustPanic(t, "crypto/aes: output not full block", func() { c.Decrypt(bytes(1), bytes(100)) }) +} + +func mustPanic(t *testing.T, msg string, f func()) { + defer func() { + err := recover() + if err == nil { + t.Errorf("function did not panic, wanted %q", msg) + } else if err != msg { + t.Errorf("got panic %v, wanted %q", err, msg) + } + }() + f() +} + func BenchmarkEncrypt(b *testing.B) { tt := encryptTests[0] c, err := NewCipher(tt.key) diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go index d931134a70e..2c6bb0a89c7 100644 --- a/libgo/go/crypto/aes/cipher.go +++ b/libgo/go/crypto/aes/cipher.go @@ -46,9 +46,21 @@ func NewCipher(key []byte) (cipher.Block, error) { func (c *aesCipher) BlockSize() int { return BlockSize } func (c *aesCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } encryptBlock(c.enc, dst, src) } func (c *aesCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } decryptBlock(c.dec, dst, src) } diff --git a/libgo/go/crypto/aes/cipher_asm.go b/libgo/go/crypto/aes/cipher_asm.go index 21369fc382c..964eaaa6f88 100644 --- a/libgo/go/crypto/aes/cipher_asm.go +++ b/libgo/go/crypto/aes/cipher_asm.go @@ -21,6 +21,7 @@ func encryptBlock(xk []uint32, dst, src []byte) { encryptBlockGo(xk, dst, src) } } + func decryptBlock(xk []uint32, dst, src []byte) { if useAsm { decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0]) @@ -28,6 +29,7 @@ func decryptBlock(xk []uint32, dst, src []byte) { decryptBlockGo(xk, dst, src) } } + func expandKey(key []byte, enc, dec []uint32) { if useAsm { rounds := 10 diff --git a/libgo/go/crypto/cipher/benchmark_test.go b/libgo/go/crypto/cipher/benchmark_test.go index 0b173a4f3f2..027b2485105 100644 --- a/libgo/go/crypto/cipher/benchmark_test.go +++ b/libgo/go/crypto/cipher/benchmark_test.go @@ -47,7 +47,7 @@ func BenchmarkAESGCMOpen1K(b *testing.B) { } // If we test exactly 1K blocks, we would generate exact multiples of -// the cipher's block size, and and the cipher stream fragments would +// the cipher's block size, and the cipher stream fragments would // always be wordsize aligned, whereas non-aligned is a more typical // use-case. const almost1K = 1024 - 5 diff --git a/libgo/go/crypto/cipher/gcm.go b/libgo/go/crypto/cipher/gcm.go index 2f748f02f7c..bdafd85fc30 100644 --- a/libgo/go/crypto/cipher/gcm.go +++ b/libgo/go/crypto/cipher/gcm.go @@ -30,9 +30,9 @@ type AEAD interface { // Open decrypts and authenticates ciphertext, authenticates the // additional data and, if successful, appends the resulting plaintext - // to dst, returning the updated slice and true. On error, nil and - // false is returned. The nonce must be NonceSize() bytes long and both - // it and the additional data must match the value passed to Seal. + // to dst, returning the updated slice. The nonce must be NonceSize() + // bytes long and both it and the additional data must match the + // value passed to Seal. // // The ciphertext and dst may alias exactly or not at all. Open(dst, nonce, ciphertext, data []byte) ([]byte, error) diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go index 5a2a65744ed..b7565a61b02 100644 --- a/libgo/go/crypto/dsa/dsa.go +++ b/libgo/go/crypto/dsa/dsa.go @@ -173,6 +173,16 @@ func GenerateKey(priv *PrivateKey, rand io.Reader) error { return nil } +// fermatInverse calculates the inverse of k in GF(P) using Fermat's method. +// This has better constant-time properties than Euclid's method (implemented +// in math/big.Int.ModInverse) although math/big itself isn't strictly +// constant-time so it's not perfect. +func fermatInverse(k, P *big.Int) *big.Int { + two := big.NewInt(2) + pMinus2 := new(big.Int).Sub(P, two) + return new(big.Int).Exp(k, pMinus2, P) +} + // Sign signs an arbitrary length hash (which should be the result of hashing a // larger message) using the private key, priv. It returns the signature as a // pair of integers. The security of the private key depends on the entropy of @@ -205,7 +215,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err } } - kInv := new(big.Int).ModInverse(k, priv.Q) + kInv := fermatInverse(k, priv.Q) r = new(big.Int).Exp(priv.G, k, priv.P) r.Mod(r, priv.Q) diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go index d02f15c34d9..1bec7437a53 100644 --- a/libgo/go/crypto/ecdsa/ecdsa.go +++ b/libgo/go/crypto/ecdsa/ecdsa.go @@ -84,6 +84,16 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int { return ret } +// fermatInverse calculates the inverse of k in GF(P) using Fermat's method. +// This has better constant-time properties than Euclid's method (implemented +// in math/big.Int.ModInverse) although math/big itself isn't strictly +// constant-time so it's not perfect. +func fermatInverse(k, N *big.Int) *big.Int { + two := big.NewInt(2) + nMinus2 := new(big.Int).Sub(N, two) + return new(big.Int).Exp(k, nMinus2, N) +} + // Sign signs an arbitrary length hash (which should be the result of hashing a // larger message) using the private key, priv. It returns the signature as a // pair of integers. The security of the private key depends on the entropy of @@ -102,7 +112,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err return } - kInv = new(big.Int).ModInverse(k, N) + kInv = fermatInverse(k, N) r, _ = priv.Curve.ScalarBaseMult(k.Bytes()) r.Mod(r, N) if r.Sign() != 0 { diff --git a/libgo/go/crypto/md5/md5block_decl.go b/libgo/go/crypto/md5/md5block_decl.go index c4d6aaaf03a..d7956a6d203 100644 --- a/libgo/go/crypto/md5/md5block_decl.go +++ b/libgo/go/crypto/md5/md5block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 386 arm +// +build amd64 amd64p32 386 arm package md5 diff --git a/libgo/go/crypto/md5/md5block_generic.go b/libgo/go/crypto/md5/md5block_generic.go index 239bf4d2152..263463e51cd 100644 --- a/libgo/go/crypto/md5/md5block_generic.go +++ b/libgo/go/crypto/md5/md5block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!386,!arm +// +build !amd64,!amd64p32,!386,!arm package md5 diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go index 0fbd7eaf579..1e741fda193 100644 --- a/libgo/go/crypto/rand/rand_unix.go +++ b/libgo/go/crypto/rand/rand_unix.go @@ -2,7 +2,7 @@ // 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 plan9 solaris +// +build darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris // Unix cryptographically secure pseudorandom number // generator. diff --git a/libgo/go/crypto/rc4/rc4_asm.go b/libgo/go/crypto/rc4/rc4_asm.go index c582a4488b8..fc71b9a6fa2 100644 --- a/libgo/go/crypto/rc4/rc4_asm.go +++ b/libgo/go/crypto/rc4/rc4_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 arm 386 +// +build amd64 amd64p32 arm 386 package rc4 diff --git a/libgo/go/crypto/rc4/rc4_ref.go b/libgo/go/crypto/rc4/rc4_ref.go index bdf5e1db2dd..1ecce1a7fbc 100644 --- a/libgo/go/crypto/rc4/rc4_ref.go +++ b/libgo/go/crypto/rc4/rc4_ref.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!arm,!386 +// +build !amd64,!amd64p32,!arm,!386 package rc4 diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go index cf174b6a21d..d9957aec1d6 100644 --- a/libgo/go/crypto/rsa/pkcs1v15.go +++ b/libgo/go/crypto/rsa/pkcs1v15.go @@ -214,7 +214,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b // hashed is the result of hashing the input message using the given hash // function and sig is the signature. A valid signature is indicated by // returning a nil error. If hash is zero then hashed is used directly. This -// isn't advisable except for interopability. +// isn't advisable except for interoperability. func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) { hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) if err != nil { diff --git a/libgo/go/crypto/rsa/pss.go b/libgo/go/crypto/rsa/pss.go index f9abec39490..18eafbc05f7 100644 --- a/libgo/go/crypto/rsa/pss.go +++ b/libgo/go/crypto/rsa/pss.go @@ -4,7 +4,7 @@ package rsa -// This file implementes the PSS signature scheme [1]. +// This file implements the PSS signature scheme [1]. // // [1] http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf @@ -189,7 +189,7 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error { // signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt. // Note that hashed must be the result of hashing the input message using the -// given hash funcion. salt is a random sequence of bytes whose length will be +// given hash function. salt is a random sequence of bytes whose length will be // later used to verify the signature. func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) { nBits := priv.N.BitLen() @@ -233,7 +233,7 @@ func (opts *PSSOptions) saltLength() int { // SignPSS calculates the signature of hashed using RSASSA-PSS [1]. // Note that hashed must be the result of hashing the input message using the -// given hash funcion. The opts argument may be nil, in which case sensible +// given hash function. The opts argument may be nil, in which case sensible // defaults are used. func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) { saltLength := opts.saltLength() diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go index c8f1febe647..bce6ba4eba3 100644 --- a/libgo/go/crypto/rsa/rsa.go +++ b/libgo/go/crypto/rsa/rsa.go @@ -60,7 +60,7 @@ type PrivateKey struct { type PrecomputedValues struct { Dp, Dq *big.Int // D mod (P-1) (or mod Q-1) - Qinv *big.Int // Q^-1 mod Q + Qinv *big.Int // Q^-1 mod P // CRTValues is used for the 3rd and subsequent primes. Due to a // historical accident, the CRT for the first two primes is handled diff --git a/libgo/go/crypto/sha1/sha1block_decl.go b/libgo/go/crypto/sha1/sha1block_decl.go index b2c68f0e8ba..24e521af1fc 100644 --- a/libgo/go/crypto/sha1/sha1block_decl.go +++ b/libgo/go/crypto/sha1/sha1block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 386 arm +// +build amd64 amd64p32 arm 386 package sha1 diff --git a/libgo/go/crypto/sha1/sha1block_generic.go b/libgo/go/crypto/sha1/sha1block_generic.go index 2c78683aa49..696e26b6257 100644 --- a/libgo/go/crypto/sha1/sha1block_generic.go +++ b/libgo/go/crypto/sha1/sha1block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!386,!arm +// +build !amd64,!amd64p32,!386,!arm package sha1 diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index 7ce2077de41..fca98bdd11c 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -82,12 +82,14 @@ const ( scsvRenegotiation uint16 = 0x00ff ) -// TLS Elliptic Curves +// CurveID is the type of a TLS identifier for an elliptic curve. See // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8 +type CurveID uint16 + const ( - curveP256 uint16 = 23 - curveP384 uint16 = 24 - curveP521 uint16 = 25 + CurveP256 CurveID = 23 + CurveP384 CurveID = 24 + CurveP521 CurveID = 25 ) // TLS Elliptic Curve Point Formats @@ -153,6 +155,7 @@ var supportedClientCertSignatureAlgorithms = []signatureAndHash{ // ConnectionState records basic TLS details about the connection. type ConnectionState struct { + Version uint16 // TLS version used by the connection (e.g. VersionTLS12) HandshakeComplete bool // TLS handshake is complete DidResume bool // connection resumes a previous TLS connection CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) @@ -198,12 +201,15 @@ type ClientSessionCache interface { Put(sessionKey string, cs *ClientSessionState) } -// A Config structure is used to configure a TLS client or server. After one -// has been passed to a TLS function it must not be modified. +// A Config structure is used to configure a TLS client or server. +// After one has been passed to a TLS function it must not be +// modified. A Config may be reused; the tls package will also not +// modify it. type Config struct { // Rand provides the source of entropy for nonces and RSA blinding. // If Rand is nil, TLS uses the cryptographic random reader in package // crypto/rand. + // The Reader must be safe for use by multiple goroutines. Rand io.Reader // Time returns the current time as the number of seconds since the epoch. @@ -290,6 +296,11 @@ type Config struct { // which is currently TLS 1.2. MaxVersion uint16 + // CurvePreferences contains the elliptic curves that will be used in + // an ECDHE handshake, in preference order. If empty, the default will + // be used. + CurvePreferences []CurveID + serverInitOnce sync.Once // guards calling (*Config).serverInit } @@ -348,6 +359,15 @@ func (c *Config) maxVersion() uint16 { return c.MaxVersion } +var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521} + +func (c *Config) curvePreferences() []CurveID { + if c == nil || len(c.CurvePreferences) == 0 { + return defaultCurvePreferences + } + return c.CurvePreferences +} + // mutualVersion returns the protocol version to use given the advertised // version of the peer. func (c *Config) mutualVersion(vers uint16) (uint16, bool) { diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go index c33549c9eff..8f7d2c144ff 100644 --- a/libgo/go/crypto/tls/conn.go +++ b/libgo/go/crypto/tls/conn.go @@ -28,6 +28,7 @@ type Conn struct { // constant after handshake; protected by handshakeMutex handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex + handshakeErr error // error resulting from handshake vers uint16 // TLS version haveVers bool // version has been negotiated config *Config // configuration passed to constructor @@ -45,9 +46,6 @@ type Conn struct { clientProtocol string clientProtocolFallback bool - // first permanent error - connErr - // input/output in, out halfConn // in.Mutex < out.Mutex rawInput *block // raw input, right off the wire @@ -57,27 +55,6 @@ type Conn struct { tmp [16]byte } -type connErr struct { - mu sync.Mutex - value error -} - -func (e *connErr) setError(err error) error { - e.mu.Lock() - defer e.mu.Unlock() - - if e.value == nil { - e.value = err - } - return err -} - -func (e *connErr) error() error { - e.mu.Lock() - defer e.mu.Unlock() - return e.value -} - // Access to net.Conn methods. // Cannot just embed net.Conn because that would // export the struct field too. @@ -105,7 +82,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error { return c.conn.SetReadDeadline(t) } -// SetWriteDeadline sets the write deadline on the underlying conneciton. +// SetWriteDeadline sets the write deadline on the underlying connection. // A zero value for t means Write will not time out. // After a Write has timed out, the TLS state is corrupt and all future writes will return the same error. func (c *Conn) SetWriteDeadline(t time.Time) error { @@ -116,6 +93,8 @@ func (c *Conn) SetWriteDeadline(t time.Time) error { // connection, either sending or receiving. type halfConn struct { sync.Mutex + + err error // first permanent error version uint16 // protocol version cipher interface{} // cipher algorithm mac macFunction @@ -129,6 +108,18 @@ type halfConn struct { inDigestBuf, outDigestBuf []byte } +func (hc *halfConn) setErrorLocked(err error) error { + hc.err = err + return err +} + +func (hc *halfConn) error() error { + hc.Lock() + err := hc.err + hc.Unlock() + return err +} + // prepareCipherSpec sets the encryption and MAC states // that a subsequent changeCipherSpec will use. func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { @@ -460,6 +451,8 @@ func (b *block) readFromUntil(r io.Reader, n int) error { m, err := r.Read(b.data[len(b.data):cap(b.data)]) b.data = b.data[0 : len(b.data)+m] if len(b.data) >= n { + // TODO(bradfitz,agl): slightly suspicious + // that we're throwing away r.Read's err here. break } if err != nil { @@ -520,16 +513,16 @@ func (c *Conn) readRecord(want recordType) error { switch want { default: c.sendAlert(alertInternalError) - return errors.New("tls: unknown record type requested") + return c.in.setErrorLocked(errors.New("tls: unknown record type requested")) case recordTypeHandshake, recordTypeChangeCipherSpec: if c.handshakeComplete { c.sendAlert(alertInternalError) - return errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete") + return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete")) } case recordTypeApplicationData: if !c.handshakeComplete { c.sendAlert(alertInternalError) - return errors.New("tls: application data record requested before handshake complete") + return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete")) } } @@ -548,7 +541,7 @@ Again: // err = io.ErrUnexpectedEOF // } if e, ok := err.(net.Error); !ok || !e.Temporary() { - c.setError(err) + c.in.setErrorLocked(err) } return err } @@ -560,18 +553,18 @@ Again: // an SSLv2 client. if want == recordTypeHandshake && typ == 0x80 { c.sendAlert(alertProtocolVersion) - return errors.New("tls: unsupported SSLv2 handshake received") + return c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received")) } vers := uint16(b.data[1])<<8 | uint16(b.data[2]) n := int(b.data[3])<<8 | int(b.data[4]) if c.haveVers && vers != c.vers { c.sendAlert(alertProtocolVersion) - return fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers) + return c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers)) } if n > maxCiphertext { c.sendAlert(alertRecordOverflow) - return fmt.Errorf("tls: oversized record received with length %d", n) + return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n)) } if !c.haveVers { // First message, be extra suspicious: @@ -584,7 +577,7 @@ Again: // it's probably not real. if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 { c.sendAlert(alertUnexpectedMessage) - return fmt.Errorf("tls: first record does not look like a TLS handshake") + return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake")) } } if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil { @@ -592,7 +585,7 @@ Again: err = io.ErrUnexpectedEOF } if e, ok := err.(net.Error); !ok || !e.Temporary() { - c.setError(err) + c.in.setErrorLocked(err) } return err } @@ -601,27 +594,27 @@ Again: b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n) ok, off, err := c.in.decrypt(b) if !ok { - return c.sendAlert(err) + c.in.setErrorLocked(c.sendAlert(err)) } b.off = off data := b.data[b.off:] if len(data) > maxPlaintext { - c.sendAlert(alertRecordOverflow) + err := c.sendAlert(alertRecordOverflow) c.in.freeBlock(b) - return c.error() + return c.in.setErrorLocked(err) } switch typ { default: - c.sendAlert(alertUnexpectedMessage) + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) case recordTypeAlert: if len(data) != 2 { - c.sendAlert(alertUnexpectedMessage) + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } if alert(data[1]) == alertCloseNotify { - c.setError(io.EOF) + c.in.setErrorLocked(io.EOF) break } switch data[0] { @@ -630,24 +623,24 @@ Again: c.in.freeBlock(b) goto Again case alertLevelError: - c.setError(&net.OpError{Op: "remote error", Err: alert(data[1])}) + c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])}) default: - c.sendAlert(alertUnexpectedMessage) + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) } case recordTypeChangeCipherSpec: if typ != want || len(data) != 1 || data[0] != 1 { - c.sendAlert(alertUnexpectedMessage) + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } err := c.in.changeCipherSpec() if err != nil { - c.sendAlert(err.(alert)) + c.in.setErrorLocked(c.sendAlert(err.(alert))) } case recordTypeApplicationData: if typ != want { - c.sendAlert(alertUnexpectedMessage) + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } c.input = b @@ -656,7 +649,7 @@ Again: case recordTypeHandshake: // TODO(rsc): Should at least pick off connection close. if typ != want { - return c.sendAlert(alertNoRenegotiation) + return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) } c.hand.Write(data) } @@ -664,7 +657,7 @@ Again: if b != nil { c.in.freeBlock(b) } - return c.error() + return c.in.err } // sendAlert sends a TLS alert message. @@ -680,7 +673,7 @@ func (c *Conn) sendAlertLocked(err alert) error { c.writeRecord(recordTypeAlert, c.tmp[0:2]) // closeNotify is a special case in that it isn't an error: if err != alertCloseNotify { - return c.setError(&net.OpError{Op: "local error", Err: err}) + return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) } return nil } @@ -766,7 +759,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) { c.tmp[0] = alertLevelError c.tmp[1] = byte(err.(alert)) c.writeRecord(recordTypeAlert, c.tmp[0:2]) - return n, c.setError(&net.OpError{Op: "local error", Err: err}) + return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err}) } } return @@ -777,7 +770,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) { // c.in.Mutex < L; c.out.Mutex < L. func (c *Conn) readHandshake() (interface{}, error) { for c.hand.Len() < 4 { - if err := c.error(); err != nil { + if err := c.in.err; err != nil { return nil, err } if err := c.readRecord(recordTypeHandshake); err != nil { @@ -788,11 +781,10 @@ func (c *Conn) readHandshake() (interface{}, error) { data := c.hand.Bytes() n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) if n > maxHandshake { - c.sendAlert(alertInternalError) - return nil, c.error() + return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError)) } for c.hand.Len() < 4+n { - if err := c.error(); err != nil { + if err := c.in.err; err != nil { return nil, err } if err := c.readRecord(recordTypeHandshake); err != nil { @@ -831,8 +823,7 @@ func (c *Conn) readHandshake() (interface{}, error) { case typeFinished: m = new(finishedMsg) default: - c.sendAlert(alertUnexpectedMessage) - return nil, alertUnexpectedMessage + return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) } // The handshake message unmarshallers @@ -841,25 +832,24 @@ func (c *Conn) readHandshake() (interface{}, error) { data = append([]byte(nil), data...) if !m.unmarshal(data) { - c.sendAlert(alertUnexpectedMessage) - return nil, alertUnexpectedMessage + return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) } return m, nil } // Write writes data to the connection. func (c *Conn) Write(b []byte) (int, error) { - if err := c.error(); err != nil { - return 0, err - } - if err := c.Handshake(); err != nil { - return 0, c.setError(err) + return 0, err } c.out.Lock() defer c.out.Unlock() + if err := c.out.err; err != nil { + return 0, err + } + if !c.handshakeComplete { return 0, alertInternalError } @@ -878,14 +868,14 @@ func (c *Conn) Write(b []byte) (int, error) { if _, ok := c.out.cipher.(cipher.BlockMode); ok { n, err := c.writeRecord(recordTypeApplicationData, b[:1]) if err != nil { - return n, c.setError(err) + return n, c.out.setErrorLocked(err) } m, b = 1, b[1:] } } n, err := c.writeRecord(recordTypeApplicationData, b) - return n + m, c.setError(err) + return n + m, c.out.setErrorLocked(err) } // Read can be made to time out and return a net.Error with Timeout() == true @@ -894,6 +884,11 @@ func (c *Conn) Read(b []byte) (n int, err error) { if err = c.Handshake(); err != nil { return } + if len(b) == 0 { + // Put this after Handshake, in case people were calling + // Read(nil) for the side effect of the Handshake. + return + } c.in.Lock() defer c.in.Unlock() @@ -902,13 +897,13 @@ func (c *Conn) Read(b []byte) (n int, err error) { // CBC IV. So this loop ignores a limited number of empty records. const maxConsecutiveEmptyRecords = 100 for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ { - for c.input == nil && c.error() == nil { + for c.input == nil && c.in.err == nil { if err := c.readRecord(recordTypeApplicationData); err != nil { // Soft error, like EAGAIN return 0, err } } - if err := c.error(); err != nil { + if err := c.in.err; err != nil { return 0, err } @@ -918,6 +913,25 @@ func (c *Conn) Read(b []byte) (n int, err error) { c.input = nil } + // If a close-notify alert is waiting, read it so that + // we can return (n, EOF) instead of (n, nil), to signal + // to the HTTP response reading goroutine that the + // connection is now closed. This eliminates a race + // where the HTTP response reading goroutine would + // otherwise not observe the EOF until its next read, + // by which time a client goroutine might have already + // tried to reuse the HTTP connection for a new + // request. + // See https://codereview.appspot.com/76400046 + // and http://golang.org/issue/3514 + if ri := c.rawInput; ri != nil && + n != 0 && err == nil && + c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert { + if recErr := c.readRecord(recordTypeApplicationData); recErr != nil { + err = recErr // will be io.EOF on closeNotify + } + } + if n != 0 || err != nil { return n, err } @@ -949,16 +963,19 @@ func (c *Conn) Close() error { func (c *Conn) Handshake() error { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() - if err := c.error(); err != nil { + if err := c.handshakeErr; err != nil { return err } if c.handshakeComplete { return nil } + if c.isClient { - return c.clientHandshake() + c.handshakeErr = c.clientHandshake() + } else { + c.handshakeErr = c.serverHandshake() } - return c.serverHandshake() + return c.handshakeErr } // ConnectionState returns basic TLS details about the connection. @@ -969,6 +986,7 @@ func (c *Conn) ConnectionState() ConnectionState { var state ConnectionState state.HandshakeComplete = c.handshakeComplete if c.handshakeComplete { + state.Version = c.vers state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go index 1b4830c725c..5c6d8396d52 100644 --- a/libgo/go/crypto/tls/generate_cert.go +++ b/libgo/go/crypto/tls/generate_cert.go @@ -58,12 +58,6 @@ func main() { notAfter := notBefore.Add(*validFor) - // end of ASN.1 time - endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC) - if notAfter.After(endOfTime) { - notAfter = endOfTime - } - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index fd1303eebb9..a320fde1bc7 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -33,13 +33,17 @@ func (c *Conn) clientHandshake() error { c.config = defaultConfig() } + if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify { + return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") + } + hello := &clientHelloMsg{ vers: c.config.maxVersion(), compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, serverName: c.config.ServerName, - supportedCurves: []uint16{curveP256, curveP384, curveP521}, + supportedCurves: c.config.curvePreferences(), supportedPoints: []uint8{pointFormatUncompressed}, nextProtoNeg: len(c.config.NextProtos) > 0, secureRenegotiation: true, @@ -497,7 +501,7 @@ func (hs *clientHandshakeState) readFinished() error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) - if err := c.error(); err != nil { + if err := c.in.error(); err != nil { return err } diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go index fbdd0b9a78f..7bcaa5eb929 100644 --- a/libgo/go/crypto/tls/handshake_messages.go +++ b/libgo/go/crypto/tls/handshake_messages.go @@ -16,7 +16,7 @@ type clientHelloMsg struct { nextProtoNeg bool serverName string ocspStapling bool - supportedCurves []uint16 + supportedCurves []CurveID supportedPoints []uint8 ticketSupported bool sessionTicket []uint8 @@ -39,7 +39,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.nextProtoNeg == m1.nextProtoNeg && m.serverName == m1.serverName && m.ocspStapling == m1.ocspStapling && - eqUint16s(m.supportedCurves, m1.supportedCurves) && + eqCurveIDs(m.supportedCurves, m1.supportedCurves) && bytes.Equal(m.supportedPoints, m1.supportedPoints) && m.ticketSupported == m1.ticketSupported && bytes.Equal(m.sessionTicket, m1.sessionTicket) && @@ -357,10 +357,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } numCurves := l / 2 - m.supportedCurves = make([]uint16, numCurves) + m.supportedCurves = make([]CurveID, numCurves) d := data[2:] for i := 0; i < numCurves; i++ { - m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1]) + m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1]) d = d[2:] } case extensionSupportedPoints: @@ -1294,6 +1294,18 @@ func eqUint16s(x, y []uint16) bool { return true } +func eqCurveIDs(x, y []CurveID) bool { + if len(x) != len(y) { + return false + } + for i, v := range x { + if y[i] != v { + return false + } + } + return true +} + func eqStrings(x, y []string) bool { if len(x) != len(y) { return false diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go index 4f569eeb138..f46aabdfd5f 100644 --- a/libgo/go/crypto/tls/handshake_messages_test.go +++ b/libgo/go/crypto/tls/handshake_messages_test.go @@ -125,9 +125,9 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { } m.ocspStapling = rand.Intn(10) > 5 m.supportedPoints = randomBytes(rand.Intn(5)+1, rand) - m.supportedCurves = make([]uint16, rand.Intn(5)+1) + m.supportedCurves = make([]CurveID, rand.Intn(5)+1) for i := range m.supportedCurves { - m.supportedCurves[i] = uint16(rand.Intn(30000)) + m.supportedCurves[i] = CurveID(rand.Intn(30000)) } if rand.Intn(10) > 5 { m.ticketSupported = true diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index 12e5ff1e589..75111eba004 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/crypto/tls/handshake_server.go @@ -117,12 +117,14 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { hs.hello = new(serverHelloMsg) supportedCurve := false + preferredCurves := config.curvePreferences() Curves: for _, curve := range hs.clientHello.supportedCurves { - switch curve { - case curveP256, curveP384, curveP521: - supportedCurve = true - break Curves + for _, supported := range preferredCurves { + if supported == curve { + supportedCurve = true + break Curves + } } } @@ -468,7 +470,7 @@ func (hs *serverHandshakeState) readFinished() error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) - if err := c.error(); err != nil { + if err := c.in.error(); err != nil { return err } diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go index 4f41ab9b78c..c3e36785b5d 100644 --- a/libgo/go/crypto/tls/handshake_server_test.go +++ b/libgo/go/crypto/tls/handshake_server_test.go @@ -121,7 +121,7 @@ func TestTLS12OnlyCipherSuites(t *testing.T) { TLS_RSA_WITH_RC4_128_SHA, }, compressionMethods: []uint8{compressionNone}, - supportedCurves: []uint16{curveP256, curveP384, curveP521}, + supportedCurves: []CurveID{CurveP256, CurveP384, CurveP521}, supportedPoints: []uint8{pointFormatUncompressed}, } @@ -195,6 +195,23 @@ func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, e return } +func TestVersion(t *testing.T) { + serverConfig := &Config{ + Certificates: testConfig.Certificates, + MaxVersion: VersionTLS11, + } + clientConfig := &Config{ + InsecureSkipVerify: true, + } + state, err := testHandshake(clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + if state.Version != VersionTLS11 { + t.Fatalf("Incorrect version %x, should be %x", state.Version, VersionTLS11) + } +} + func TestCipherSuitePreference(t *testing.T) { serverConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go index 861faf0e85a..f38b701f1ba 100644 --- a/libgo/go/crypto/tls/key_agreement.go +++ b/libgo/go/crypto/tls/key_agreement.go @@ -141,7 +141,7 @@ func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices .. // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a // ServerKeyExchange given the signature type being used and the client's -// advertized list of supported signature and hash combinations. +// advertised list of supported signature and hash combinations. func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) { if len(clientSignatureAndHashes) == 0 { // If the client didn't specify any signature_algorithms @@ -163,6 +163,20 @@ func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatu return 0, errors.New("tls: client doesn't support any common hash functions") } +func curveForCurveID(id CurveID) (elliptic.Curve, bool) { + switch id { + case CurveP256: + return elliptic.P256(), true + case CurveP384: + return elliptic.P384(), true + case CurveP521: + return elliptic.P521(), true + default: + return nil, false + } + +} + // ecdheRSAKeyAgreement implements a TLS key agreement where the server // generates a ephemeral EC public/private key pair and signs it. The // pre-master secret is then calculated using ECDH. The signature may @@ -176,23 +190,16 @@ type ecdheKeyAgreement struct { } func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { - var curveid uint16 - -Curve: - for _, c := range clientHello.supportedCurves { - switch c { - case curveP256: - ka.curve = elliptic.P256() - curveid = c - break Curve - case curveP384: - ka.curve = elliptic.P384() - curveid = c - break Curve - case curveP521: - ka.curve = elliptic.P521() - curveid = c - break Curve + var curveid CurveID + preferredCurves := config.curvePreferences() + +NextCandidate: + for _, candidate := range preferredCurves { + for _, c := range clientHello.supportedCurves { + if candidate == c { + curveid = c + break NextCandidate + } } } @@ -200,6 +207,11 @@ Curve: return nil, errors.New("tls: no supported elliptic curves offered") } + var ok bool + if ka.curve, ok = curveForCurveID(curveid); !ok { + return nil, errors.New("tls: preferredCurves includes unsupported curve") + } + var x, y *big.Int var err error ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand()) @@ -293,19 +305,13 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell return errServerKeyExchange } if skx.key[0] != 3 { // named curve - return errors.New("server selected unsupported curve") + return errors.New("tls: server selected unsupported curve") } - curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2]) + curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2]) - switch curveid { - case curveP256: - ka.curve = elliptic.P256() - case curveP384: - ka.curve = elliptic.P384() - case curveP521: - ka.curve = elliptic.P521() - default: - return errors.New("server selected unsupported curve") + var ok bool + if ka.curve, ok = curveForCurveID(curveid); !ok { + return errors.New("tls: server selected unsupported curve") } publicLen := int(skx.key[3]) diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA index 0d2294a7107..00722cba945 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 52 cc 57 59 e6 |....Y...U..R.WY.| -00000010 12 4c 15 38 e6 b7 2c 9e b5 82 bb b5 9d f5 71 4a |.L.8..,.......qJ| -00000020 66 21 30 c2 44 69 ec 7c 8a 37 8b 20 1e 9c 78 3a |f!0.Di.|.7. ..x:| -00000030 bf d0 e0 37 6b 88 5c 8f 90 a8 92 c3 f6 b7 ad fc |...7k.\.........| -00000040 56 4a 50 34 ce 8f 08 e5 08 40 71 9b c0 09 00 00 |VJP4.....@q.....| +00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 03 46 |....Y...U..S...F| +00000010 0f 84 c4 cb 55 ef 85 f6 4f d7 0e e1 4b 10 d4 bb |....U...O...K...| +00000020 35 87 2d f3 d7 18 ec 4e 95 4b f4 20 28 82 94 d9 |5.-....N.K. (...| +00000030 df c4 fc ee 21 23 c1 e2 76 3e 7b 09 af 2c 39 23 |....!#..v>{..,9#| +00000040 f8 46 6c 31 88 42 f0 79 de 37 2b 00 c0 09 00 00 |.Fl1.B.y.7+.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,20 +47,20 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 00 |*............A..| -00000280 3d 87 12 2c c5 fd db 6e ab 0c 7c 54 85 fc d3 13 |=..,...n..|T....| -00000290 34 1e 13 83 2c 60 05 67 83 f0 3a cc c6 27 84 63 |4...,`.g..:..'.c| -000002a0 90 4e 25 26 0f 03 ca f3 ae 7e 44 c6 94 0d e4 1b |.N%&.....~D.....| -000002b0 4a 53 e2 d7 f0 5c 83 64 37 c0 0f d1 9e 86 de 00 |JS...\.d7.......| -000002c0 8a 30 81 87 02 41 4f 85 6d 11 af d1 27 9c de 21 |.0...AO.m...'..!| -000002d0 d7 e5 96 ad 4f 6a a1 5c 2b 63 22 0e 4f 22 77 16 |....Oj.\+c".O"w.| -000002e0 ec 6e db 38 1a df 28 4e ee 9e a4 c1 e7 d3 02 74 |.n.8..(N.......t| -000002f0 07 3f 58 7f 82 51 2d 9e 78 6b bd 28 77 20 c1 40 |.?X..Q-.xk.(w .@| -00000300 09 71 ba b9 23 c7 82 02 42 01 13 1b 64 c4 1f c6 |.q..#...B...d...| -00000310 1f f3 f4 51 8c 64 92 37 5e f0 5c 11 c9 ee 43 55 |...Q.d.7^.\...CU| -00000320 a0 83 52 8b d9 2d d1 22 2c 2e 2c e0 04 a6 59 b3 |..R..-.",.,...Y.| -00000330 f9 33 d8 e4 9a 0b 2b 95 c6 41 5d 60 a3 d1 9f 31 |.3....+..A]`...1| -00000340 14 5d a3 31 6e 70 f1 e7 35 5a f9 16 03 01 00 0e |.].1np..5Z......| +00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 4f |*............A.O| +00000280 47 16 72 98 9e 9f 2e 8e 78 e9 0f fe 95 83 7b aa |G.r.....x.....{.| +00000290 e5 3d c0 7d cf 83 bd 22 0b fd 48 f1 a7 49 a5 7d |.=.}..."..H..I.}| +000002a0 8e 0c 83 7f e1 2d 71 03 cc 90 09 ab f7 35 81 48 |.....-q......5.H| +000002b0 a4 1e 7d 87 21 23 12 58 2c 47 f3 af c7 6c 71 00 |..}.!#.X,G...lq.| +000002c0 8a 30 81 87 02 42 00 b4 03 38 60 43 d9 32 ef 64 |.0...B...8`C.2.d| +000002d0 5a 9c 91 95 0d 10 21 53 c7 78 f8 bf 50 ed 13 5d |Z.....!S.x..P..]| +000002e0 c3 e7 71 d6 11 04 f1 e4 9d ce 17 99 8d 1a 87 1f |..q.............| +000002f0 cb dd f8 1b ae cd bc 4a 77 ab 7c 50 bf 73 c3 ea |.......Jw.|P.s..| +00000300 d6 df 88 56 f6 b1 03 83 02 41 66 3d fb 4e 7e af |...V.....Af=.N~.| +00000310 4e c1 60 fe 09 fa 7e 74 99 66 7f de b4 b2 74 89 |N.`...~t.f....t.| +00000320 1c a4 cf 74 1a 55 a5 be 74 f9 36 21 3d ae c8 c3 |...t.U..t.6!=...| +00000330 24 8e ad db a3 26 67 8f 98 27 e3 93 ee d9 5c fb |$....&g..'....\.| +00000340 85 82 e2 13 c3 50 ab e9 f6 39 2b 16 03 01 00 0e |.....P...9+.....| 00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......| >>> Flow 3 (client to server) 00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| @@ -108,22 +108,22 @@ 000002a0 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 4b 49 |.jB..~~1...f.AKI| 000002b0 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 c0 ab |.......P.m..Q...| 000002c0 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 87 f1 |...>K.S:.e......| -000002d0 67 d0 f2 06 28 4e 51 4e fd f0 01 c1 1f 1d 1c 32 |g...(NQN.......2| -000002e0 1f 91 5d 06 f5 44 1b a0 1b 61 43 6b de 81 bd 14 |..]..D...aCk....| -000002f0 03 01 00 01 01 16 03 01 00 30 fe bb 82 52 2d 8a |.........0...R-.| -00000300 81 87 ba 2c 18 5b 93 07 78 30 85 f3 5f 4f df 3f |...,.[..x0.._O.?| -00000310 1a fc 01 b9 a5 32 99 d3 40 0b ef c5 b8 32 f4 7e |.....2..@....2.~| -00000320 d2 93 0f 19 24 87 c5 18 e2 8b |....$.....| +000002d0 67 d0 f2 06 28 4e 51 4e fd f0 01 be 41 3c 52 42 |g...(NQN....A<RB| +000002e0 10 44 73 88 3e 44 24 bb 2e 77 01 77 6f a8 ac 14 |.Ds.>D$..w.wo...| +000002f0 03 01 00 01 01 16 03 01 00 30 a3 da 45 22 96 83 |.........0..E"..| +00000300 59 90 e9 6b ec 3b 77 50 05 89 e6 0c 61 d1 1d 2b |Y..k.;wP....a..+| +00000310 da d4 49 bf b9 c6 dd ad c3 9c 82 bd 53 62 e8 57 |..I.........Sb.W| +00000320 a4 6a e7 9f b1 d5 39 77 88 6d |.j....9w.m| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 84 a0 90 cb 8b |..........0.....| -00000010 43 ad 66 06 ef f1 4b 5c 85 cc 4e 12 60 44 b4 be |C.f...K\..N.`D..| -00000020 ed 94 23 69 bf 7a cc e9 a7 17 db 9a ec d5 9b 15 |..#i.z..........| -00000030 92 62 5e bb ac db 78 50 d1 b2 0c |.b^...xP...| +00000000 14 03 01 00 01 01 16 03 01 00 30 a4 45 dd 99 df |..........0.E...| +00000010 66 ae f5 c7 bd 1a eb 6a ff ac a6 38 14 81 b5 07 |f......j...8....| +00000020 86 24 80 f1 09 59 ad 33 3d 43 ed 9e 43 b1 1e 9f |.$...Y.3=C..C...| +00000030 bd 8c b3 e0 41 83 a1 34 91 c5 a1 |....A..4...| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 b4 fd 9e 0a 69 49 16 72 52 8b 81 |.... ....iI.rR..| -00000010 50 87 07 77 d4 9a 07 06 88 e0 43 43 32 a0 7c f9 |P..w......CC2.|.| -00000020 13 88 3f 87 36 17 03 01 00 20 6e 96 f6 4c f8 8d |..?.6.... n..L..| -00000030 1b 15 ff 3e 7c 5e fc f0 81 6e 5e 26 3c 42 96 dc |...>|^...n^&<B..| -00000040 69 79 b8 73 9c 1d eb 31 5d 94 15 03 01 00 20 b4 |iy.s...1]..... .| -00000050 68 2c 4d 74 ed a5 bc f4 e3 56 bd 3e 19 78 fc 8a |h,Mt.....V.>.x..| -00000060 1e f0 4c 7e f9 11 de e1 15 38 9b ed 6f 9b 34 |..L~.....8..o.4| +00000000 17 03 01 00 20 ae e3 ae 7f 2d e3 a2 f7 1b 4e 69 |.... ....-....Ni| +00000010 cb 18 c6 68 42 f8 de 61 92 4c fa d6 19 7c 8c 09 |...hB..a.L...|..| +00000020 82 e2 f2 32 19 17 03 01 00 20 2a 77 65 1f c1 fd |...2..... *we...| +00000030 5e 37 b7 15 f6 1f 4c 7f 5f 89 52 b4 32 27 4d 17 |^7....L._.R.2'M.| +00000040 33 c6 e8 50 ac 70 c8 b9 2d 0a 15 03 01 00 20 e0 |3..P.p..-..... .| +00000050 cb ce 07 80 55 a0 46 ca a7 25 4c 5f 9d 7c 73 37 |....U.F..%L_.|s7| +00000060 de 72 6d 36 a8 e4 be fd 2a e7 f8 8d 14 80 b7 |.rm6....*......| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA index 36f6eb16371..c0be82491e2 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 51 02 00 00 4d 03 01 52 cc 57 59 78 |....Q...M..R.WYx| -00000010 63 f8 d6 ea 32 6f 22 7c 7b fb ab 48 c8 3b d9 ed |c...2o"|{..H.;..| -00000020 5b 01 e0 0a 36 d8 26 57 56 dd e4 20 ed c9 d8 e5 |[...6.&WV.. ....| -00000030 5c 2a 1b b6 d2 bd 32 5d 42 fe 4b d1 89 4c 1f b0 |\*....2]B.K..L..| -00000040 5d fc 1f d4 4a f3 ef 06 28 1a d3 09 00 05 00 00 |]...J...(.......| +00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 ed |....Q...M..S....| +00000010 86 9c 56 84 5a d3 7d d7 f3 4e 6f 2c 69 0d f0 59 |..V.Z.}..No,i..Y| +00000020 a5 d1 de 2d 03 2f dd 63 c3 ab fa 20 30 d6 5a 24 |...-./.c... 0.Z$| +00000030 5c 31 67 36 8d 4c 43 e1 64 c4 8a 2c a5 fd 39 92 |\1g6.LC.d..,..9.| +00000040 c5 6f 58 47 a3 fe 63 14 98 92 11 90 00 05 00 00 |.oXG..c.........| 00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -109,17 +109,17 @@ 000002e0 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 4b 49 |.jB..~~1...f.AKI| 000002f0 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 c0 ab |.......P.m..Q...| 00000300 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 87 f1 |...>K.S:.e......| -00000310 67 d0 f2 06 28 4e 51 4e fd f0 01 65 a4 80 ad 7e |g...(NQN...e...~| -00000320 a3 bc 1d 1a 83 3a db 30 c7 67 96 cf e7 aa dc 14 |.....:.0.g......| -00000330 03 01 00 01 01 16 03 01 00 24 d9 38 91 04 a4 ac |.........$.8....| -00000340 eb d7 4c 7a c6 07 25 72 a0 f7 3f 6d 37 cc db 40 |..Lz..%r..?m7..@| -00000350 c0 26 9b be 03 55 2d 24 c5 b3 4f 6d 56 c4 |.&...U-$..OmV.| +00000310 67 d0 f2 06 28 4e 51 4e fd f0 01 47 e7 c9 d9 23 |g...(NQN...G...#| +00000320 21 6b 87 d2 55 e3 c9 f7 eb 86 d5 1e 50 df d5 14 |!k..U.......P...| +00000330 03 01 00 01 01 16 03 01 00 24 95 62 42 be 90 39 |.........$.bB..9| +00000340 68 ae f5 77 47 21 14 b9 ac ee 81 2d e3 9e c7 34 |h..wG!.....-...4| +00000350 3a 00 5c c9 12 1d c0 5a 7c e7 ef e0 cd fd |:.\....Z|.....| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 b8 8d b1 db 80 |..........$.....| -00000010 1d 26 9e 41 d0 48 40 0d 6a 94 e6 42 93 60 58 d1 |.&.A.H@.j..B.`X.| -00000020 b2 13 7c 6f ec 1c f5 2a 1e 82 14 6f 0f 13 a7 |..|o...*...o...| +00000000 14 03 01 00 01 01 16 03 01 00 24 ea 98 c0 fb 86 |..........$.....| +00000010 87 7a 2e e1 c7 68 61 3e 5b cc da 1f d6 7b ab 5a |.z...ha>[....{.Z| +00000020 a0 ae a2 cf d0 54 44 19 12 db 75 2b 8c 73 8c |.....TD...u+.s.| >>> Flow 5 (client to server) -00000000 17 03 01 00 1a ea f3 99 a3 b1 7e 9a 29 ad 31 18 |..........~.).1.| -00000010 1b 5b 7c 71 ae 5b c6 ba 8e 8e 36 f6 ab 2c dd 15 |.[|q.[....6..,..| -00000020 03 01 00 16 82 cf f4 83 05 4c 86 e2 47 cc 6f 2c |.........L..G.o,| -00000030 6d 50 c6 09 3b fd a8 5e 12 3c |mP..;..^.<| +00000000 17 03 01 00 1a f3 28 77 31 33 4c b3 7c 4b 75 61 |......(w13L.|Kua| +00000010 38 69 6b ae c9 36 ab 2e 56 16 29 6a 9a 00 2f 15 |8ik..6..V.)j../.| +00000020 03 01 00 16 6b ed 68 18 ed ff 44 39 9b 4a e4 a2 |....k.h...D9.J..| +00000030 cd 79 ef 2a 3e 5a 4d b1 5d 56 |.y.*>ZM.]V| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA index 9e4ea665443..3e6dbc271a9 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 52 cc 57 58 fc |....Y...U..R.WX.| -00000010 46 e4 45 fc 07 cb ec 16 cc ce 87 96 0e f6 d9 c7 |F.E.............| -00000020 49 2e ec 53 30 07 cd 01 1d 49 2e 20 2b bc 5c 11 |I..S0....I. +.\.| -00000030 90 55 88 3f ec e4 30 b3 58 e7 d2 82 32 15 dd b4 |.U.?..0.X...2...| -00000040 1f e2 4c 1d 08 f9 a0 8d 75 8b 63 c2 c0 09 00 00 |..L.....u.c.....| +00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 4f |....Y...U..S...O| +00000010 73 06 2d 72 41 36 a1 b2 d3 50 97 55 8c c5 f1 43 |s.-rA6...P.U...C| +00000020 37 1f 1a 2a fe 51 70 0b 2f 25 9e 20 50 61 86 80 |7..*.Qp./%. Pa..| +00000030 9a 9c 6d 6f c9 ea 5c ce 0c b7 7c ce e3 be d0 e5 |..mo..\...|.....| +00000040 be d0 c4 80 78 c3 c7 17 0c 2d 8e c8 c0 09 00 00 |....x....-......| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,21 +47,21 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 5e |*............A.^| -00000280 6d f1 9c b6 ec 5b c9 fc 16 b2 75 63 90 82 23 8f |m....[....uc..#.| -00000290 14 6f 53 b1 23 06 fa c7 b9 b4 d2 59 3d 4f 94 a2 |.oS.#......Y=O..| -000002a0 02 af 0a 1e 94 f7 4d 31 c1 b3 a7 c4 67 89 67 da |......M1....g.g.| -000002b0 71 de 5a 1d ca 79 b8 f3 9e 6a 42 f8 60 8b 2a 00 |q.Z..y...jB.`.*.| -000002c0 8a 30 81 87 02 42 00 85 32 00 54 ab af 7a 95 32 |.0...B..2.T..z.2| -000002d0 f9 c7 e3 34 23 ed 1c 5d 7b a2 78 bf f1 a3 3f 53 |...4#..]{.x...?S| -000002e0 ad c4 56 1f f6 98 9e 29 66 ef 52 21 80 d6 21 e7 |..V....)f.R!..!.| -000002f0 61 fd 75 90 37 ec 13 0a f4 c2 47 a4 a7 41 87 24 |a.u.7.....G..A.$| -00000300 0c c6 c0 09 f0 54 c4 df 02 41 30 3e a5 6c a2 5d |.....T...A0>.l.]| -00000310 76 66 fb a2 f5 2d ef ee 63 63 b4 9a db 84 23 db |vf...-..cc....#.| -00000320 e9 0d 5f 43 cc 6b ef 4a 7f a2 1d 6b 6c 7f 1f ba |.._C.k.J...kl...| -00000330 52 5f 6c 3f cc 77 54 ef 75 1f c2 1e da 6f d3 07 |R_l?.wT.u....o..| -00000340 23 7d 54 6d 40 88 0d 6e 72 90 8e 16 03 01 00 0e |#}Tm@..nr.......| -00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......| +00000270 2a 16 03 01 00 d6 0c 00 00 d2 03 00 17 41 04 b1 |*............A..| +00000280 0f 0f 4a 18 ed 25 32 b3 a3 19 ed 4b 61 b6 eb e4 |..J..%2....Ka...| +00000290 d3 f7 77 13 ac 9f 60 c7 8d 6d cb f1 ee 99 1a 71 |..w...`..m.....q| +000002a0 68 aa d3 a7 70 7f 38 d0 f6 23 ab 9a f6 dd 19 4f |h...p.8..#.....O| +000002b0 ce 10 ef d5 cf 64 85 2f 75 f6 20 06 4b f0 b9 00 |.....d./u. .K...| +000002c0 8b 30 81 88 02 42 01 00 b9 6b 80 91 59 0a 48 3f |.0...B...k..Y.H?| +000002d0 72 16 96 8f 21 2c 28 e4 6d 03 74 66 35 16 7d ec |r...!,(.m.tf5.}.| +000002e0 c7 08 9b 52 b5 05 d9 38 d8 b7 51 42 a7 4a 9f 9b |...R...8..QB.J..| +000002f0 1a 37 14 de c5 f5 16 96 83 81 58 d3 a6 1e ce 8a |.7........X.....| +00000300 bc 19 47 30 fe c5 85 55 02 42 01 4f 61 59 68 85 |..G0...U.B.OaYh.| +00000310 c7 64 23 22 f6 83 53 cc 58 38 25 b5 ce 74 c1 68 |.d#"..S.X8%..t.h| +00000320 9f 32 72 33 ea c9 62 e0 26 63 92 e3 5f 34 10 0b |.2r3..b.&c.._4..| +00000330 3c d5 83 fe 9f 67 69 ef 33 6b 19 c1 ec d6 6c 35 |<....gi.3k....l5| +00000340 89 33 17 d3 9d 93 e2 e5 6e 89 9a a1 16 03 01 00 |.3......n.......| +00000350 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......| >>> Flow 3 (client to server) 00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| @@ -100,29 +100,29 @@ 00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 86 |..h.A.Vk.Z......| -00000250 0f 00 00 82 00 80 0d cf 9a c6 5e 57 60 b9 a4 87 |..........^W`...| -00000260 ae 83 25 4a d5 af 02 69 4d a1 0b ac 0c 97 58 30 |..%J...iM.....X0| -00000270 cc 9d 45 6a eb e3 a5 b1 f9 63 9c 05 04 8f 55 b3 |..Ej.....c....U.| -00000280 5b 7c 5b f6 36 2d b1 89 84 21 ce a6 ce be 66 c6 |[|[.6-...!....f.| -00000290 06 4a 07 8a a0 13 ee f1 52 ea 65 71 b7 49 b7 49 |.J......R.eq.I.I| -000002a0 dc 0a d0 c6 c3 69 ef 67 97 6b d8 41 e0 d1 a4 66 |.....i.g.k.A...f| -000002b0 cc 3c ba 4a 63 46 af e1 7f 16 2e 73 5c 69 17 45 |.<.JcF.....s\i.E| -000002c0 b3 2d e2 7c 92 4c de 02 c6 97 d3 9c e0 d5 9c 22 |.-.|.L........."| -000002d0 30 21 11 5e 1c 1a 14 03 01 00 01 01 16 03 01 00 |0!.^............| -000002e0 30 db d7 9e 46 3e 5a 60 5d 21 22 34 ca 9a 3b 3c |0...F>Z`]!"4..;<| -000002f0 a6 41 12 42 b9 78 d7 39 4b 51 d0 d0 3e 7e ba 4c |.A.B.x.9KQ..>~.L| -00000300 7c 8d 4b 03 e5 fe 4c 59 a6 9f a1 5d 46 54 56 61 ||.K...LY...]FTVa| -00000310 33 |3| +00000250 0f 00 00 82 00 80 20 2c 5a 08 3a 00 33 50 19 b2 |...... ,Z.:.3P..| +00000260 0f ba 6c 76 7f 5c 92 e2 78 55 3e 32 32 bb 33 bc |..lv.\..xU>22.3.| +00000270 ab a9 34 e0 83 cf 82 cd 9e 6b 3f 9d e6 49 61 29 |..4......k?..Ia)| +00000280 8b b4 ed e8 12 cd a9 52 86 11 48 64 08 61 72 8d |.......R..Hd.ar.| +00000290 d6 6a ac 42 cc e4 07 5f 08 56 9f 2f c5 35 d3 9b |.j.B..._.V./.5..| +000002a0 e9 0d 91 82 c0 e9 bb 9f a9 8f df 96 85 08 9a 69 |...............i| +000002b0 a4 93 b3 72 37 ba f9 b1 a4 0b b0 9f 43 6a 15 ec |...r7.......Cj..| +000002c0 79 b8 fd 9c 1f 5f 0d 2c 56 33 c7 15 d5 4a b7 82 |y...._.,V3...J..| +000002d0 ea 44 80 20 c5 80 14 03 01 00 01 01 16 03 01 00 |.D. ............| +000002e0 30 c9 c0 7c d7 57 d3 00 ab 87 eb 78 56 6b a1 69 |0..|.W.....xVk.i| +000002f0 1d fa ec ae 38 f3 ef 5d 49 19 0d 4b f0 73 63 af |....8..]I..K.sc.| +00000300 89 b6 cb 76 cf fb b9 c1 99 98 06 0a 54 67 a0 6e |...v........Tg.n| +00000310 e7 |.| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 72 c2 59 5a f3 |..........0r.YZ.| -00000010 6f db 45 d0 4b 8c b9 49 25 25 cd eb 00 c7 99 6c |o.E.K..I%%.....l| -00000020 a7 4d 5a 4c f3 05 7d b0 fb 97 1a 40 0d 42 ca ad |.MZL..}....@.B..| -00000030 df 57 6c 47 40 13 49 47 09 7c 2e |.WlG@.IG.|.| +00000000 14 03 01 00 01 01 16 03 01 00 30 20 db fd ed ed |..........0 ....| +00000010 7c d5 bf 8f 06 3b 86 1b c1 60 7d a4 74 e9 a6 c9 ||....;...`}.t...| +00000020 f5 7c c7 f4 65 91 06 d5 53 88 d7 57 a4 22 b6 1f |.|..e...S..W."..| +00000030 f1 02 e9 79 36 e6 a1 22 51 3a 4c |...y6.."Q:L| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 c5 99 ba cc 39 bb db 07 27 3c 05 |.... ....9...'<.| -00000010 fb 79 ce bd ec 8c 67 20 c8 46 3b ad bf 8c 66 fc |.y....g .F;...f.| -00000020 55 de 73 0f 71 17 03 01 00 20 7b 3e 2b 60 c0 df |U.s.q.... {>+`..| -00000030 ca b1 c4 19 28 de 3e 8e 20 8b 4a 4a 07 52 5f 8c |....(.>. .JJ.R_.| -00000040 1b 4f 54 15 69 31 f7 46 03 94 15 03 01 00 20 fc |.OT.i1.F...... .| -00000050 b9 06 b4 6d 60 28 3f 4f b2 9a e8 1c 74 d3 15 a6 |...m`(?O....t...| -00000060 7b 49 85 d0 2f 83 bf 4d 7f 60 6e 18 bf c7 34 |{I../..M.`n...4| +00000000 17 03 01 00 20 00 66 51 6a 14 ca ea e2 21 48 74 |.... .fQj....!Ht| +00000010 c4 c1 6e b9 8b 23 af 7c 33 c9 00 f8 0b ec ab 35 |..n..#.|3......5| +00000020 e7 42 0a d1 ae 17 03 01 00 20 00 1c 6d 60 75 5d |.B....... ..m`u]| +00000030 b3 fb 40 2e e0 b7 0d 48 f4 87 ac d4 bf ea 01 0d |..@....H........| +00000040 fe 10 0d 05 04 43 6b 19 ed f2 15 03 01 00 20 f8 |.....Ck....... .| +00000050 03 ac 62 4b 1f db 2e d2 4e 00 c3 a4 57 3c 0a 62 |..bK....N...W<.b| +00000060 05 a0 ef bd 2b 9b 9a 63 27 72 d7 d8 f1 8d 84 |....+..c'r.....| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA index c21579c9329..94e686004f9 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 51 02 00 00 4d 03 01 52 cc 57 58 bd |....Q...M..R.WX.| -00000010 25 74 73 5e 31 99 73 f1 c6 a1 9b f0 07 09 97 d7 |%ts^1.s.........| -00000020 b6 b9 65 a3 08 16 0b 4c 4a 06 00 20 ef 0b 97 cb |..e....LJ.. ....| -00000030 3c cf 05 b6 fe 62 d7 15 29 cf c8 56 e0 7e d7 92 |<....b..)..V.~..| -00000040 11 86 86 49 a0 b1 12 2f dc 15 f7 67 00 05 00 00 |...I.../...g....| +00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 73 |....Q...M..S...s| +00000010 ee 5f 70 a4 aa 0d be d7 46 a3 25 3f e3 5d ef 7b |._p.....F.%?.].{| +00000020 73 49 7c b6 82 4d 99 2f 31 fc 8b 20 2d a3 33 7c |sI|..M./1.. -.3|| +00000030 a5 c3 85 86 ba 61 4d 05 b0 5e d3 5e 88 6e c3 4b |.....aM..^.^.n.K| +00000040 95 d3 e9 67 f1 96 24 58 7a 6f e6 c5 00 05 00 00 |...g..$Xzo......| 00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -101,24 +101,24 @@ 00000260 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000270 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000280 35 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 01 00 86 |5..C.0oUN.p.....| -00000290 0f 00 00 82 00 80 41 42 bb be 9d a4 d3 e9 24 f2 |......AB......$.| -000002a0 6c 7d b0 68 10 7a 88 e3 41 5d 24 f9 b2 a6 4c 31 |l}.h.z..A]$...L1| -000002b0 2b 90 51 49 65 3d d4 4b 1f 69 93 91 c0 a2 ec 2c |+.QIe=.K.i.....,| -000002c0 d0 48 e1 64 7f ef 8b da be 8c 0a 19 8b ff c7 37 |.H.d...........7| -000002d0 3d b8 8c 6d 2f 28 bd ba 96 6e c5 ed fa 29 c5 42 |=..m/(...n...).B| -000002e0 f2 24 b9 b5 55 1e 12 46 a5 bb 7c 41 2a b0 02 44 |.$..U..F..|A*..D| -000002f0 68 89 e9 92 e3 ad 50 44 f1 18 e7 e4 ee 2c 74 40 |h.....PD.....,t@| -00000300 82 39 a3 cf 30 54 fb 53 42 f1 18 28 8a f4 ef 65 |.9..0T.SB..(...e| -00000310 f2 33 6a e7 2a 48 14 03 01 00 01 01 16 03 01 00 |.3j.*H..........| -00000320 24 d8 a8 6d 1c 31 f7 cc 06 57 ef cf 7e 9b ac d3 |$..m.1...W..~...| -00000330 6b 50 b2 d8 c6 41 a2 c8 a6 f5 53 b3 d4 af e8 71 |kP...A....S....q| -00000340 88 9e 7e d9 57 |..~.W| +00000290 0f 00 00 82 00 80 0f 4c d2 b2 f0 94 6d 61 d1 2c |.......L....ma.,| +000002a0 db 6f 79 03 bd 40 b2 d2 1d 61 ef 83 1b 4a 0c 7b |.oy..@...a...J.{| +000002b0 c5 73 1e 1a 81 e7 67 0a d6 aa 2d 04 04 cc 0e 4b |.s....g...-....K| +000002c0 2e da 96 7f 15 6c 05 ee c4 53 7e 33 89 28 7d db |.....l...S~3.(}.| +000002d0 a1 77 43 ba a3 51 a9 1c b9 f5 ec 9a 8d eb 2c 46 |.wC..Q........,F| +000002e0 5c 33 59 6b 16 af de f4 9b 80 76 a3 22 30 5d bb |\3Yk......v."0].| +000002f0 02 b9 77 96 8a db 36 9f 54 95 00 d8 58 e1 aa 04 |..w...6.T...X...| +00000300 98 c9 0c 32 ae 62 81 12 0c f6 1b 76 c6 58 a7 8c |...2.b.....v.X..| +00000310 0e d8 b7 8e ed 0f 14 03 01 00 01 01 16 03 01 00 |................| +00000320 24 1d c0 20 02 2d da 69 54 29 8c ff af 5c 56 a8 |$.. .-.iT)...\V.| +00000330 eb d0 09 95 29 8f 52 8c e2 7b 9f 36 3e 47 a0 33 |....).R..{.6>G.3| +00000340 2e 63 a2 24 93 |.c.$.| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 71 90 c8 76 87 |..........$q..v.| -00000010 7f 07 da de 41 93 59 f4 e9 64 73 49 d3 15 b0 7d |....A.Y..dsI...}| -00000020 d7 86 06 85 62 71 9f 57 db 1a 81 82 ed 9b df |....bq.W.......| +00000000 14 03 01 00 01 01 16 03 01 00 24 99 e8 fb 65 f4 |..........$...e.| +00000010 95 ae 8b 71 cc 5d a4 95 a7 27 98 fd 16 3f 7a 1a |...q.]...'...?z.| +00000020 b6 bd bf 0a 58 72 77 97 1f 8e b1 dd 4b 12 12 |....Xrw.....K..| >>> Flow 5 (client to server) -00000000 17 03 01 00 1a 35 83 3e 0a 4d 7b 58 4d 6b 9e d7 |.....5.>.M{XMk..| -00000010 77 32 dd b0 93 25 d1 fc e2 08 ad 2c 91 fd ce 15 |w2...%.....,....| -00000020 03 01 00 16 56 9c d9 6e 45 4c 95 8a 2d 75 7e 52 |....V..nEL..-u~R| -00000030 0a 75 0a f0 a1 52 91 c4 d2 b4 |.u...R....| +00000000 17 03 01 00 1a 42 70 c0 89 78 12 5c 91 7e 88 2d |.....Bp..x.\.~.-| +00000010 2f 8f be f2 f2 12 9d 81 ae 78 08 38 5e 6d 1b 15 |/........x.8^m..| +00000020 03 01 00 16 1a 64 b1 6f 8a ff d3 63 6a c7 b8 95 |.....d.o...cj...| +00000030 3d b0 87 bc 62 e9 88 5b 26 bd |=...b..[&.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES index b89d02c3687..30c4c6b831a 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 52 cc 57 58 a5 |....Y...U..R.WX.| -00000010 0d f3 9c e1 2f 44 99 dc f2 26 bc c2 44 4a 0f ab |..../D...&..DJ..| -00000020 6d 40 3b 5a 98 21 43 9e c0 39 03 20 03 46 6f c2 |m@;Z.!C..9. .Fo.| -00000030 bd 1f bc cc 2d b2 eb 22 91 23 df 20 28 c5 df ea |....-..".#. (...| -00000040 70 1a dc 07 b9 19 a1 d0 03 74 81 a8 c0 09 00 00 |p........t......| +00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 b2 |....Y...U..S....| +00000010 e0 f6 f6 b5 c9 5b 28 d0 5d 58 1b 6f 4e 2b 9d 05 |.....[(.]X.oN+..| +00000020 2a b9 b4 da 45 cf f3 10 b2 23 44 20 f8 4d 59 05 |*...E....#D .MY.| +00000030 ad 27 f2 a0 ee 7f ec cc 20 dc e7 a2 1b 07 b3 a5 |.'...... .......| +00000040 37 7e 61 3d d6 5c 03 cf cc f5 9b ca c0 09 00 00 |7~a=.\..........| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,20 +47,20 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 3c |*............A.<| -00000280 f8 33 94 22 ad fb 45 01 10 5c 8e b1 09 19 da de |.3."..E..\......| -00000290 21 0a 09 72 af 25 6f 2f 63 4d 8c 6b b6 a6 00 02 |!..r.%o/cM.k....| -000002a0 4d 6c fe 71 9e 45 74 13 db b5 7a a1 74 f0 16 35 |Ml.q.Et...z.t..5| -000002b0 50 fd ab 45 4c 64 9f 4d 80 a9 5c 85 ee 20 33 00 |P..ELd.M..\.. 3.| -000002c0 8a 30 81 87 02 42 01 73 bc ac 1a 30 11 5f 93 95 |.0...B.s...0._..| -000002d0 00 03 ba d6 f3 02 cd c9 a0 15 bf 9a 1a 59 24 1e |.............Y$.| -000002e0 3e 99 6b da b1 81 e1 eb da fd 8e 73 d6 94 1e ce |>.k........s....| -000002f0 04 cf 41 33 cd e5 8d f0 e2 50 b9 9b 49 df bc 51 |..A3.....P..I..Q| -00000300 2d 5c 12 5c b3 8b 81 73 02 41 3c bf 11 5c 10 be |-\.\...s.A<..\..| -00000310 f2 e7 59 2f 9a d7 0e 49 a3 17 7d 20 cc bc 17 1f |..Y/...I..} ....| -00000320 2d 1b 19 90 52 c5 16 08 b3 3c b0 33 9d 03 45 75 |-...R....<.3..Eu| -00000330 0c 3f ac 7b 0b b2 69 f4 a5 7c fc 49 a6 54 55 84 |.?.{..i..|.I.TU.| -00000340 2f 19 f1 de 1b 92 3d fb 68 5d ea 16 03 01 00 04 |/.....=.h]......| +00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 da |*............A..| +00000280 5a fd 09 e5 d6 c0 70 41 5e 3a 87 eb df 0c ad 90 |Z.....pA^:......| +00000290 22 8a 2f 90 81 0c 24 00 68 92 f3 d5 95 2f 93 43 |"./...$.h..../.C| +000002a0 e9 58 2d 18 28 62 ee 33 5b 21 2e 49 87 21 4d 32 |.X-.(b.3[!.I.!M2| +000002b0 32 19 b3 ba fe 2d 9a 85 12 0e a1 77 08 06 75 00 |2....-.....w..u.| +000002c0 8a 30 81 87 02 42 01 91 14 fc 68 74 95 10 4b d4 |.0...B....ht..K.| +000002d0 67 60 12 46 bb b0 f6 98 77 a3 41 b8 01 5c 49 54 |g`.F....w.A..\IT| +000002e0 9e 3e 81 e7 97 a3 b9 73 6e 15 74 67 be e5 d9 eb |.>.....sn.tg....| +000002f0 8b 87 c5 22 ab ab 58 28 4f d1 b6 80 94 1b f5 f7 |..."..X(O.......| +00000300 12 43 ef 0a c7 3e 1a 76 02 41 7a 00 49 cb 9f 3b |.C...>.v.Az.I..;| +00000310 91 6e 38 58 0a d3 d0 d1 ee 67 f0 b6 5d cd fa 23 |.n8X.....g..]..#| +00000320 b6 98 43 af 9c 71 90 1e 1d 50 a2 6e 61 5b f2 92 |..C..q...P.na[..| +00000330 b4 69 73 f2 3b 54 bf 1c 9d 05 19 97 e4 4e 41 9e |.is.;T.......NA.| +00000340 f2 9a 76 77 9a 86 43 1f 1f 30 a2 16 03 01 00 04 |..vw..C..0......| 00000350 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| @@ -68,20 +68,20 @@ 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 01 00 30 c7 cf 21 f8 0c 94 5b 11 ef ee |.....0..!...[...| -00000060 d0 d3 3a d5 ba 2d 19 8b 5b 53 68 94 f1 49 8b 19 |..:..-..[Sh..I..| -00000070 f3 80 d5 55 52 7d 72 af 38 73 35 df 6e 04 4b ca |...UR}r.8s5.n.K.| -00000080 64 b7 ff c3 e1 eb |d.....| +00000050 01 16 03 01 00 30 88 60 65 b2 d7 51 1f ad 96 56 |.....0.`e..Q...V| +00000060 4e 0a 20 eb b5 b0 1a dd 4c f6 1a cf d4 5c 47 c4 |N. .....L....\G.| +00000070 9c 7c a0 36 dd d1 1b 96 91 99 c0 a7 2d 9a 7c 42 |.|.6........-.|B| +00000080 51 d1 de 87 2b a4 |Q...+.| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 59 2c 4c 03 7f |..........0Y,L..| -00000010 aa a8 ca d8 2a b0 35 71 ea 3a 2b d4 b1 9f 13 f9 |....*.5q.:+.....| -00000020 c2 7b fb 21 52 15 73 e6 71 d4 65 8e 21 25 1a 63 |.{.!R.s.q.e.!%.c| -00000030 03 d3 a5 6b 17 0e e7 18 84 17 d8 |...k.......| +00000000 14 03 01 00 01 01 16 03 01 00 30 86 6c b5 94 69 |..........0.l..i| +00000010 2e e0 55 a2 4d a8 63 f2 5b 1f ae 34 21 c8 21 6a |..U.M.c.[..4!.!j| +00000020 00 b6 56 ed 4e 2a b0 ff 01 2f da ce a1 c0 41 03 |..V.N*.../....A.| +00000030 a9 1b 6e 2e e1 88 50 ba 62 14 88 |..n...P.b..| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 8d 73 59 92 ce 93 78 e6 63 cf 9d |.... .sY...x.c..| -00000010 bc 44 40 76 c7 66 3f 15 3a 0a 91 9b 94 49 ec cc |.D@v.f?.:....I..| -00000020 7c 1a 6c b2 85 17 03 01 00 20 2e 6a dd 85 be 12 ||.l...... .j....| -00000030 c1 45 e4 04 bf 46 70 19 12 d1 1a 28 f6 22 30 a2 |.E...Fp....(."0.| -00000040 fe 98 a8 11 c2 c4 19 46 c6 7e 15 03 01 00 20 a7 |.......F.~.... .| -00000050 71 3d 87 94 9d 6c c5 dd de 44 54 47 d5 06 37 82 |q=...l...DTG..7.| -00000060 36 e0 c2 e5 91 74 a8 88 28 2f 87 7d a1 a7 e3 |6....t..(/.}...| +00000000 17 03 01 00 20 a6 63 0a 2f a5 dc e1 fb cb 7b 1f |.... .c./.....{.| +00000010 f2 da 74 c3 ff e9 f5 8b 9c 5f 0c d3 f7 1f 44 e6 |..t......_....D.| +00000020 90 13 5c 48 50 17 03 01 00 20 c7 75 b5 ff bc 09 |..\HP.... .u....| +00000030 34 f2 45 db 0d 22 08 8e f1 35 cd b6 0f b0 eb 2a |4.E.."...5.....*| +00000040 b7 1a d0 8e 14 a4 54 84 f9 dc 15 03 01 00 20 e0 |......T....... .| +00000050 36 3d aa b3 a9 b4 20 23 ca 9e 8c 5d fc a8 c8 b7 |6=.... #...]....| +00000060 f5 c2 b6 d0 5a e2 ce a5 7b 68 a0 48 86 95 6a |....Z...{h.H..j| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES index ae03ea4584d..868f0ceb0e5 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 52 cc 57 58 f3 |....Y...U..R.WX.| -00000010 e4 e3 02 40 35 40 24 91 0a 0b 54 1b 46 0d c1 46 |...@5@$...T.F..F| -00000020 7f 9c dd 08 ec 9c 63 73 13 cd e8 20 3c c2 72 a5 |......cs... <.r.| -00000030 8d 4e 66 14 83 b1 27 c9 51 7e a6 46 7c 38 e1 66 |.Nf...'.Q~.F|8.f| -00000040 3f f6 9c e2 8d e0 51 29 fc 76 ee d0 c0 13 00 00 |?.....Q).v......| +00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 21 |....Y...U..S...!| +00000010 67 b5 2b 34 fb 62 d7 36 4f cf 68 2e 29 39 d0 28 |g.+4.b.6O.h.)9.(| +00000020 3a 02 32 82 8f 95 de 62 d6 03 77 20 e6 98 56 cd |:.2....b..w ..V.| +00000030 96 24 d1 b9 4d eb 51 19 bb b7 71 f4 9c 29 32 d4 |.$..M.Q...q..)2.| +00000040 e5 c6 0a 54 e0 4a 20 29 3e bd 06 0d c0 13 00 00 |...T.J )>.......| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| 00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| @@ -58,40 +58,40 @@ 000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| 00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| 00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| -00000320 d9 16 03 01 00 cb 0c 00 00 c7 03 00 17 41 04 30 |.............A.0| -00000330 a3 31 3d 66 ce 80 2a fb 1d 11 66 f6 35 cb c9 d2 |.1=f..*...f.5...| -00000340 53 fd 18 37 84 75 7e 00 55 92 0c 6d e5 40 46 77 |S..7.u~.U..m.@Fw| -00000350 d8 17 d4 81 13 74 90 e0 7c 4b 58 25 65 99 8e 18 |.....t..|KX%e...| -00000360 9f d7 af e0 70 f8 c6 99 13 2d 0e 28 32 02 40 00 |....p....-.(2.@.| -00000370 80 b3 34 d4 4a d7 c1 8e 1d f6 23 ef 04 0c d6 bb |..4.J.....#.....| -00000380 40 8c 85 0f ce a6 8e d2 29 3d 81 0f 47 ce 59 dc |@.......)=..G.Y.| -00000390 dc 56 68 b1 11 af 98 3a 07 4b 7a d9 6e 08 c5 ff |.Vh....:.Kz.n...| -000003a0 b2 54 06 72 f3 d2 19 22 df ee 90 fc 8a 4d 76 c1 |.T.r...".....Mv.| -000003b0 c2 d4 af d7 77 82 79 3d 12 0f 9c 56 28 a6 43 ea |....w.y=...V(.C.| -000003c0 a3 71 c2 af bf 52 40 4a fa c7 3e d3 ae 8e 84 42 |.q...R@J..>....B| -000003d0 5f fd 9f a7 0f 94 8c fa 15 86 23 28 be 2b 3a 32 |_.........#(.+:2| -000003e0 cb e5 18 5c 2d d6 d9 94 5f a4 b7 05 d0 a0 ab aa |...\-..._.......| -000003f0 c3 16 03 01 00 04 0e 00 00 00 |..........| +00000320 d9 16 03 01 00 cb 0c 00 00 c7 03 00 17 41 04 05 |.............A..| +00000330 45 33 f8 4b e9 96 0e 4a fd ec 54 76 21 9b 24 8a |E3.K...J..Tv!.$.| +00000340 75 0b 80 84 c7 30 2b 22 f0 85 57 a4 a9 79 d6 f6 |u....0+"..W..y..| +00000350 6d 80 b0 71 d9 66 c9 6c dd 76 fc 32 d0 c6 bc 52 |m..q.f.l.v.2...R| +00000360 2f f1 c9 62 17 53 76 ec be a6 1c 93 f2 b4 5d 00 |/..b.Sv.......].| +00000370 80 72 d9 20 52 70 7c 03 b1 33 fa 51 23 cd 05 97 |.r. Rp|..3.Q#...| +00000380 6f d6 89 2f 8d 2e 3a 17 32 eb f2 ff 6b 39 70 5e |o../..:.2...k9p^| +00000390 21 41 8d 69 02 c8 9a 17 19 e4 48 9b 51 c3 7f 9b |!A.i......H.Q...| +000003a0 8d 4a 83 97 07 0e 30 f1 8b 6b e9 92 12 01 d6 96 |.J....0..k......| +000003b0 f2 1a a2 10 7f 59 87 16 1a fb 55 67 68 fc 78 c6 |.....Y....Ugh.x.| +000003c0 57 ac 05 dd f3 6f 77 84 eb ae b0 33 2d 19 2c ba |W....ow....3-.,.| +000003d0 b8 ae 9f 95 69 85 95 45 5e 37 f4 17 17 9b 03 c1 |....i..E^7......| +000003e0 50 b1 36 42 bd 60 5c 8b d8 b6 f3 c8 34 c8 9d 9d |P.6B.`\.....4...| +000003f0 75 16 03 01 00 04 0e 00 00 00 |u.........| >>> Flow 3 (client to server) 00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 01 00 30 34 e6 9a 20 8c 33 d7 85 ae 83 |.....04.. .3....| -00000060 f1 8f 46 68 63 3f a3 23 88 f8 00 9b 01 a7 80 c6 |..Fhc?.#........| -00000070 8b 45 6e 5a c1 2f 62 5f 70 b6 20 1e 58 18 53 6b |.EnZ./b_p. .X.Sk| -00000080 e2 cb ce 2c 97 7c |...,.|| +00000050 01 16 03 01 00 30 ca d1 1b 08 27 9b 44 e7 e9 b4 |.....0....'.D...| +00000060 90 16 4d 30 4e 65 5c 0d 47 ba 46 86 cf c9 80 e7 |..M0Ne\.G.F.....| +00000070 64 31 f5 a1 9e dc 39 15 d3 be 16 4f c7 90 b6 62 |d1....9....O...b| +00000080 5d 6d 7f 41 4e 3e |]m.AN>| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 ff 81 ba a6 cc |..........0.....| -00000010 c5 25 83 eb 65 99 39 4d 19 39 c1 8c cf b5 30 58 |.%..e.9M.9....0X| -00000020 aa 6f e1 f4 f7 da 88 14 39 c0 1b 5a f3 05 bd 8c |.o......9..Z....| -00000030 6b af 52 32 0f 1e 87 0c 7a 39 3a |k.R2....z9:| +00000000 14 03 01 00 01 01 16 03 01 00 30 98 81 24 8e cd |..........0..$..| +00000010 b6 48 2f 80 de 8e 24 3c cd 02 67 80 34 97 d7 92 |.H/...$<..g.4...| +00000020 78 c2 44 3d 5d 05 eb 88 76 79 46 7a c3 fa ca 73 |x.D=]...vyFz...s| +00000030 45 82 ad c1 81 00 ca 40 c1 2f 13 |E......@./.| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 72 b0 d7 a5 88 02 64 29 65 4b d5 |.... r.....d)eK.| -00000010 f7 0b 74 bd df af ce 2d 02 6b 01 37 fb 44 80 e6 |..t....-.k.7.D..| -00000020 f4 e1 17 e6 7f 17 03 01 00 20 18 8a 94 81 86 56 |......... .....V| -00000030 eb 7e 77 48 03 ce b4 8c 2b 75 b8 06 eb 66 5f 77 |.~wH....+u...f_w| -00000040 df 98 1f cd 6d bd 39 38 06 fc 15 03 01 00 20 d1 |....m.98...... .| -00000050 bd 74 3b eb a2 f6 be ad ab df 5f 99 c2 92 fd 9b |.t;......._.....| -00000060 e7 9a 03 a5 f4 00 99 8c f8 85 34 2d 15 a0 30 |..........4-..0| +00000000 17 03 01 00 20 ee 19 59 67 67 a9 8b db 99 87 50 |.... ..Ygg.....P| +00000010 01 e2 02 c1 d5 6d 36 79 af aa ec 1b 80 0e b6 5e |.....m6y.......^| +00000020 5f fa 03 01 cc 17 03 01 00 20 ec e2 04 b7 3b a5 |_........ ....;.| +00000030 f2 e0 13 1f 17 48 e7 6e d3 eb f0 fa 36 ef 6e 2e |.....H.n....6.n.| +00000040 fb ea c8 39 c4 5f 4b 28 d4 50 15 03 01 00 20 c7 |...9._K(.P.... .| +00000050 45 ff fb c7 07 0c d8 0e 35 a3 c5 31 47 b7 03 0e |E.......5..1G...| +00000060 14 c8 29 fd 53 70 5f 15 ac d2 1c 4c 69 fb d6 |..).Sp_....Li..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 index 1a6c42c1458..395d53bbabb 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 01 00 51 02 00 00 4d 03 01 52 cc 57 58 d1 |....Q...M..R.WX.| -00000010 c7 22 72 55 68 fb 69 12 2d 85 02 b7 66 93 40 d1 |."rUh.i.-...f.@.| -00000020 2d 32 57 a8 f2 06 62 93 a0 39 b6 20 08 37 44 11 |-2W...b..9. .7D.| -00000030 73 db 68 79 6d 98 30 f7 bf a2 9b a3 cb c0 03 cb |s.hym.0.........| -00000040 7f 79 e9 31 08 ce 93 17 25 6d c3 c4 00 05 00 00 |.y.1....%m......| +00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 76 |....Q...M..S...v| +00000010 e8 45 7f 57 f3 42 4b 33 0b 06 fa a6 fa c4 3d 84 |.E.W.BK3......=.| +00000020 5a 45 dc 93 41 a5 8d 79 6e 8f 11 20 e7 c6 29 2b |ZE..A..yn.. ..)+| +00000030 ff 4a 6e 63 67 a6 10 cb 49 19 46 1e 5e 0a d5 70 |.Jncg...I.F.^..p| +00000040 96 88 9a 32 48 ef c3 4a 45 4c 6d e0 00 05 00 00 |...2H..JELm.....| 00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -69,15 +69,15 @@ 00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 01 00 01 |5..C.0oUN.p.....| -00000090 01 16 03 01 00 24 54 26 aa 7d 70 99 51 f1 bc d6 |.....$T&.}p.Q...| -000000a0 e9 0b 4b c7 b2 02 8c ed 36 c9 7f b8 f7 82 29 3a |..K.....6.....):| -000000b0 0b 6a c0 b4 ef 38 3f e8 8a bf |.j...8?...| +00000090 01 16 03 01 00 24 cd c0 68 dc 2e 69 cc c7 5b c5 |.....$..h..i..[.| +000000a0 3f bd 40 cf a0 0f 41 34 ce 16 37 10 26 c8 3f d1 |?.@...A4..7.&.?.| +000000b0 46 3b ad 7b b0 31 f3 c5 36 e7 |F;.{.1..6.| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 9a 52 2f b1 3c |..........$.R/.<| -00000010 71 92 5c 81 68 a8 27 4c b8 a9 4e 69 81 41 01 a2 |q.\.h.'L..Ni.A..| -00000020 99 d4 0c dc 15 7b 52 b5 ee be a6 6f 70 88 91 |.....{R....op..| +00000000 14 03 01 00 01 01 16 03 01 00 24 ea 77 6f 3c 42 |..........$.wo<B| +00000010 12 16 51 de e8 b6 f9 85 06 d9 6d 05 75 50 2b 27 |..Q.......m.uP+'| +00000020 93 b7 6b 65 e9 14 99 48 53 3e be e4 be 03 5d |..ke...HS>....]| >>> Flow 5 (client to server) -00000000 17 03 01 00 1a b5 06 d1 18 a6 4b 26 21 47 be 14 |..........K&!G..| -00000010 79 2e 63 49 84 1e 83 31 3b cb 97 14 94 5b 09 15 |y.cI...1;....[..| -00000020 03 01 00 16 9d d6 d0 2a 65 f2 7e 31 20 e6 63 89 |.......*e.~1 .c.| -00000030 b3 76 92 20 db b8 e6 25 54 1b |.v. ...%T.| +00000000 17 03 01 00 1a 9e ae ca 55 df c4 d9 47 04 55 dd |........U...G.U.| +00000010 3b 33 e1 a6 16 6f a1 94 b1 9b 4d 0d cb 6c 3b 15 |;3...o....M..l;.| +00000020 03 01 00 16 92 5d 76 07 e9 b7 31 29 09 c5 b1 09 |.....]v...1)....| +00000030 2d 64 3d 85 8d f1 d1 40 54 b8 |-d=....@T.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES index 935aac14910..9f941f8ef18 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 02 00 59 02 00 00 55 03 02 52 cc 57 58 b6 |....Y...U..R.WX.| -00000010 e0 47 f9 28 99 af 27 4c 21 20 d6 b1 ae 4e d4 62 |.G.(..'L! ...N.b| -00000020 8a 24 f4 62 47 77 a5 78 4b d0 09 20 5b 17 6b 88 |.$.bGw.xK.. [.k.| -00000030 8a ab 8c 0b 63 d9 c3 06 6d 13 e3 27 22 38 ee 69 |....c...m..'"8.i| -00000040 88 7d e1 18 f8 ef 93 62 f4 06 1f ab c0 09 00 00 |.}.....b........| +00000000 16 03 02 00 59 02 00 00 55 03 02 53 04 f1 02 1c |....Y...U..S....| +00000010 d1 1c 6a 5f 7a 5c 26 69 92 cd ee c3 57 ed 96 90 |..j_z\&i....W...| +00000020 e3 c5 f1 ee 8b ee 99 5f 46 2c e6 20 c8 50 6a a4 |......._F,. .Pj.| +00000030 4b 93 e6 da ba 6d d4 87 f6 75 a8 9d 44 db b5 43 |K....m...u..D..C| +00000040 df 12 57 de a4 f1 bc fb b8 7a 3f 6a c0 09 00 00 |..W......z?j....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 02 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,21 +47,21 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 02 00 d6 0c 00 00 d2 03 00 17 41 04 79 |*............A.y| -00000280 48 bb 4c 30 4f 5c fe 5e 37 65 dc 65 90 d4 4a 7f |H.L0O\.^7e.e..J.| -00000290 8c fc 45 b6 4f fb 11 2b 7c 20 cf 94 83 79 f6 cc |..E.O..+| ...y..| -000002a0 c6 d6 44 0c ad ae 5c fc fd 87 0f b9 51 03 dc 38 |..D...\.....Q..8| -000002b0 d8 44 a8 75 18 7e d1 c6 3e 9e 0a 45 85 92 4b 00 |.D.u.~..>..E..K.| -000002c0 8b 30 81 88 02 42 01 dd a7 0b d6 69 3c b5 fc 06 |.0...B.....i<...| -000002d0 8b c3 37 1d 12 be 0d 80 4a e4 d5 4e df c0 5c 7d |..7.....J..N..\}| -000002e0 ca 61 f2 3c 87 83 e0 de 22 0f 25 78 f0 21 ec ca |.a.<....".%x.!..| -000002f0 8e 62 28 24 10 3e d9 7d 30 d7 f1 bd dc c6 98 a9 |.b($.>.}0.......| -00000300 c4 3f 85 8f 47 8c 8e b7 02 42 01 3c 61 1e ee e9 |.?..G....B.<a...| -00000310 44 2d ae 57 d1 2f 04 59 16 f0 80 03 3e a1 fe 1f |D-.W./.Y....>...| -00000320 5f 54 b2 e1 b2 c0 07 3c ad d9 9f 95 8d 79 7d 9b |_T.....<.....y}.| -00000330 8e 68 cc b9 7f 08 b3 c9 24 1f a9 37 18 60 52 54 |.h......$..7.`RT| -00000340 5e 55 9c 36 1c 06 29 6b 7b 95 3e 73 16 03 02 00 |^U.6..)k{.>s....| -00000350 04 0e 00 00 00 |.....| +00000270 2a 16 03 02 00 d4 0c 00 00 d0 03 00 17 41 04 7b |*............A.{| +00000280 c4 00 37 35 51 de c3 f2 a4 95 2c 19 21 3e a6 94 |..75Q.....,.!>..| +00000290 7b fd 04 d7 b7 1c 56 e6 af 3c ee 36 cb 55 e6 f0 |{.....V..<.6.U..| +000002a0 e6 24 34 6b 8a 02 66 71 f9 e2 f5 a6 c9 d7 6c dc |.$4k..fq......l.| +000002b0 65 59 ff 1c c9 ec a9 8b 07 d6 52 2c 01 3c c3 00 |eY........R,.<..| +000002c0 89 30 81 86 02 41 74 89 1a 31 72 e6 8b c0 4a ce |.0...At..1r...J.| +000002d0 8f 5a 49 a7 52 2d 6d b9 8b 50 17 62 2a 99 d6 3b |.ZI.R-m..P.b*..;| +000002e0 02 85 41 4d 34 53 b5 09 bd e3 ac 16 c1 9b e9 83 |..AM4S..........| +000002f0 cc 83 e3 9c 23 34 67 71 72 d4 05 a2 34 f7 08 29 |....#4gqr...4..)| +00000300 62 43 2e cc bc 08 01 02 41 59 de 5a d0 dd d7 6b |bC......AY.Z...k| +00000310 db 9c 35 29 79 f8 96 91 56 74 1f 18 7b ee 25 83 |..5)y...Vt..{.%.| +00000320 f2 37 0e 77 ab 38 fb 5e 04 0b 09 d9 b4 1f 3f be |.7.w.8.^......?.| +00000330 2e e3 60 e3 96 f3 29 c1 6d 8f 56 1b fd 62 14 48 |..`...).m.V..b.H| +00000340 e3 d9 2a ea 2f be 93 d0 8b 31 16 03 02 00 04 0e |..*./....1......| +00000350 00 00 00 |...| >>> Flow 3 (client to server) 00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -69,21 +69,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 42 9f 9d 29 fc 0e e3 9d 6d 89 |......B..)....m.| -00000070 38 c3 6f d8 0f 0f 41 69 24 b8 44 a8 81 28 56 80 |8.o...Ai$.D..(V.| -00000080 c2 a2 cd b8 27 84 4d f1 f0 5c dc df 94 a7 a4 05 |....'.M..\......| -00000090 84 b9 f6 5c b4 50 |...\.P| +00000060 00 00 00 00 00 00 b6 98 a2 a9 48 34 12 6b 0a 94 |..........H4.k..| +00000070 89 fc 38 04 63 5a 6f 63 36 3e d9 35 12 64 8c 28 |..8.cZoc6>.5.d.(| +00000080 99 a6 cf 2e 57 e3 14 6d 0a 8a ab f0 a6 58 37 7c |....W..m.....X7|| +00000090 96 04 d3 71 bc d4 |...q..| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 40 5f 24 a7 68 9c |..........@_$.h.| -00000010 cc 93 4c fc a1 25 3d 71 43 88 d9 17 9b c9 99 6b |..L..%=qC......k| -00000020 01 00 24 a8 ca b3 52 3e cf 2f f5 3e 80 16 c9 cb |..$...R>./.>....| -00000030 52 20 c3 f5 e0 8f a2 d9 f9 3d 86 c5 44 f6 52 31 |R .......=..D.R1| -00000040 82 3a f9 fb d1 f6 43 5b b8 28 bc |.:....C[.(.| +00000000 14 03 02 00 01 01 16 03 02 00 40 c5 01 c9 0a b0 |..........@.....| +00000010 d8 ca 5e c1 19 dc 37 6c 2e a0 b3 11 a8 87 65 5a |..^...7l......eZ| +00000020 09 41 b9 fe 53 c4 c9 76 97 6d 7f ac c0 be d2 07 |.A..S..v.m......| +00000030 84 e5 5b 78 37 34 ee da 3b cb 3e 82 52 79 91 44 |..[x74..;.>.Ry.D| +00000040 b4 e4 1c ec 3a c0 c0 9d cd ff 13 |....:......| >>> Flow 5 (client to server) 00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 18 60 dd b8 15 76 04 ae 8c e9 09 |......`...v.....| -00000020 84 8c c2 04 38 b2 45 3d cb ea 9b cf 11 1a 38 67 |....8.E=......8g| -00000030 cd ff 89 4c 8c 15 03 02 00 30 00 00 00 00 00 00 |...L.....0......| -00000040 00 00 00 00 00 00 00 00 00 00 f3 b4 a0 68 1b 3b |.............h.;| -00000050 5c c7 e7 70 32 5f 19 4f a4 bf 0a 57 bc a0 7d be |\..p2_.O...W..}.| -00000060 91 46 5a 8e 02 25 67 20 d0 c2 |.FZ..%g ..| +00000010 00 00 00 00 00 46 60 13 39 2b 2f 72 95 ed 0e aa |.....F`.9+/r....| +00000020 69 6e b4 64 3e 83 43 d0 f9 7f 37 7c 1d b9 ce 11 |in.d>.C...7|....| +00000030 d9 41 66 60 6d 15 03 02 00 30 00 00 00 00 00 00 |.Af`m....0......| +00000040 00 00 00 00 00 00 00 00 00 00 b1 26 d0 5d 08 98 |...........&.]..| +00000050 eb 28 42 74 31 58 42 95 c5 ad 1a 92 0a f5 5f ed |.(Bt1XB......._.| +00000060 45 98 e0 90 e5 a3 b6 8b 8d 18 |E.........| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES index 9bfaa75deb1..fc723396a4f 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 02 00 59 02 00 00 55 03 02 52 cc 57 58 39 |....Y...U..R.WX9| -00000010 f8 48 dc e0 ba ad e3 f6 6e bf 6b 9e e0 34 53 4f |.H......n.k..4SO| -00000020 cd 16 7a 31 ac 23 de 31 3c 4b 0d 20 41 92 79 b5 |..z1.#.1<K. A.y.| -00000030 e0 f6 1c 25 da db 35 3b 58 61 04 52 7f ac da 64 |...%..5;Xa.R...d| -00000040 0d 31 f0 52 55 5d ec 37 94 21 aa 6f c0 13 00 00 |.1.RU].7.!.o....| +00000000 16 03 02 00 59 02 00 00 55 03 02 53 04 f1 02 fe |....Y...U..S....| +00000010 17 8b 79 ad 93 2e d3 89 66 9b 5d 9b b4 03 3e ba |..y.....f.]...>.| +00000020 65 2a f1 55 f9 3c 33 de 2c a7 47 20 fa 4f 82 11 |e*.U.<3.,.G .O..| +00000030 96 81 d0 70 2e 65 b3 68 2e 3a 6d d7 6c 74 22 33 |...p.e.h.:m.lt"3| +00000040 d4 ae 6c aa c8 f0 c7 20 8b 10 21 e7 c0 13 00 00 |..l.... ..!.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 02 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| 00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| @@ -58,20 +58,20 @@ 000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| 00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| 00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| -00000320 d9 16 03 02 00 cb 0c 00 00 c7 03 00 17 41 04 0a |.............A..| -00000330 be f8 00 24 e0 50 bf 90 12 25 b9 26 3b 7f 4a a2 |...$.P...%.&;.J.| -00000340 b3 4b b1 76 db 53 0d 83 9b 35 57 2f 64 ad 03 d1 |.K.v.S...5W/d...| -00000350 f9 1b ef cf 48 8a a8 a9 4c df d3 7b 7d e8 a0 68 |....H...L..{}..h| -00000360 2b 20 b4 4f 1c e3 11 1d bf a9 bd 58 e4 4a 3e 00 |+ .O.......X.J>.| -00000370 80 2a 64 fb 5f 8f f5 bb 6d 48 2c 7d a6 c0 f6 b2 |.*d._...mH,}....| -00000380 3d 2b 75 83 07 fd b8 9d 50 a1 ec 1c 09 85 69 4f |=+u.....P.....iO| -00000390 a3 39 8e 2f b4 94 76 b1 8d 03 3f 76 01 7e 22 90 |.9./..v...?v.~".| -000003a0 08 58 40 0d d7 65 c1 49 d5 7e 0d 28 62 ec b6 58 |.X@..e.I.~.(b..X| -000003b0 6f ff 83 21 65 e7 8b f5 51 32 5f 39 e8 9e 85 d4 |o..!e...Q2_9....| -000003c0 65 1c a8 a8 70 82 5e db d7 c6 4a 2d 2e ef c3 b3 |e...p.^...J-....| -000003d0 73 ca 13 5b 99 19 e3 4d cb 4a 9f 42 3c b7 79 fb |s..[...M.J.B<.y.| -000003e0 70 33 f7 a7 59 cb 76 a7 7c f3 8a 9a 5d fd 12 74 |p3..Y.v.|...]..t| -000003f0 5a 16 03 02 00 04 0e 00 00 00 |Z.........| +00000320 d9 16 03 02 00 cb 0c 00 00 c7 03 00 17 41 04 26 |.............A.&| +00000330 56 18 02 e5 66 d4 aa 24 7e ae 39 e5 ca 78 6c c1 |V...f..$~.9..xl.| +00000340 90 02 c3 c4 ad 79 2c 47 a8 bf 54 e2 8a 22 b6 ef |.....y,G..T.."..| +00000350 99 d4 7a 7f 8f 78 6a 78 4e 14 2a 16 0d bb 54 38 |..z..xjxN.*...T8| +00000360 59 1f 7a 53 1b c7 73 10 89 4b de c3 66 39 7a 00 |Y.zS..s..K..f9z.| +00000370 80 3a 88 38 c8 15 07 ab 2f 0f 0d cb 19 07 84 ac |.:.8..../.......| +00000380 24 fd 8b d2 9d 05 45 c6 11 c3 d6 84 58 95 5a 08 |$.....E.....X.Z.| +00000390 b9 a4 2c c0 41 4e 34 e0 b2 24 98 94 b7 67 27 50 |..,.AN4..$...g'P| +000003a0 ba 82 35 28 a9 bf 16 ee e3 7b 49 9c 4c 81 80 69 |..5(.....{I.L..i| +000003b0 d7 aa ed 46 ea 9a 68 c4 97 b7 11 d4 35 91 74 5e |...F..h.....5.t^| +000003c0 54 10 34 83 cd c4 06 18 49 7d 7a 28 c9 53 06 73 |T.4.....I}z(.S.s| +000003d0 00 7b 04 b6 d8 36 a7 4b 67 7f 81 30 94 de 40 4d |.{...6.Kg..0..@M| +000003e0 18 f8 c4 b7 02 00 44 8e bc 72 06 24 53 15 74 72 |......D..r.$S.tr| +000003f0 8d 16 03 02 00 04 0e 00 00 00 |..........| >>> Flow 3 (client to server) 00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -79,21 +79,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 9a 7d f8 d5 af e5 5d 16 a2 39 |.......}....]..9| -00000070 94 a5 de f6 ae 71 ba b7 b5 6e 9e a7 05 37 ed ff |.....q...n...7..| -00000080 b4 c3 d9 4e d5 d5 3c 84 7e 3f a4 68 23 3b 52 ab |...N..<.~?.h#;R.| -00000090 d7 30 3b 63 ed b1 |.0;c..| +00000060 00 00 00 00 00 00 8a 87 81 38 35 c0 4c bb f8 12 |.........85.L...| +00000070 fa 75 04 cd 1e 3a 61 96 93 c8 fb 07 d1 6d b4 55 |.u...:a......m.U| +00000080 0f b5 0f 07 35 0a 96 ce 5c 6f 24 62 d3 68 e4 b0 |....5...\o$b.h..| +00000090 5d be 81 37 c2 9c |]..7..| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 40 df 38 36 f9 ee |..........@.86..| -00000010 03 f3 92 e1 3b 81 21 60 3a 46 3a 2c fc 2f 6a 01 |....;.!`:F:,./j.| -00000020 a4 04 a6 f4 09 f9 bf 1f 73 a6 c6 04 83 8a ae 39 |........s......9| -00000030 43 d7 8d 88 8e 6c f2 da 0d a9 82 b5 4e b0 41 c9 |C....l......N.A.| -00000040 5a 00 93 9b 8c 60 3c 08 fa aa 91 |Z....`<....| +00000000 14 03 02 00 01 01 16 03 02 00 40 66 36 8d f8 8c |..........@f6...| +00000010 7f db 38 e8 39 df f8 2f cb 88 9c 14 d9 89 10 b4 |..8.9../........| +00000020 be 59 88 d7 f3 73 62 af a3 42 66 6e 74 38 64 9f |.Y...sb..Bfnt8d.| +00000030 16 79 09 d7 14 7e 91 8a 70 73 63 28 30 58 fe cc |.y...~..psc(0X..| +00000040 42 45 d6 37 fb 9e 8c c1 01 af 34 |BE.7......4| >>> Flow 5 (client to server) 00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 85 20 30 5e 6e e6 ab a0 2c 66 7a |...... 0^n...,fz| -00000020 f9 88 3b ee c9 5b 5c 0b a3 7a 94 f0 8a ab 61 e0 |..;..[\..z....a.| -00000030 7f 93 78 79 61 15 03 02 00 30 00 00 00 00 00 00 |..xya....0......| -00000040 00 00 00 00 00 00 00 00 00 00 e0 de 16 23 01 0a |.............#..| -00000050 cf 90 1b 96 6a 14 f2 c9 af e2 20 49 ce b4 82 bf |....j..... I....| -00000060 bf ed 7a 28 e1 ed 8e e7 18 c6 |..z(......| +00000010 00 00 00 00 00 31 0b e3 9d 2a 05 83 19 7d 10 36 |.....1...*...}.6| +00000020 23 dc da fe 00 ab d3 aa 8f ce 28 5f 08 fd b7 59 |#.........(_...Y| +00000030 1e 00 2e 25 5a 15 03 02 00 30 00 00 00 00 00 00 |...%Z....0......| +00000040 00 00 00 00 00 00 00 00 00 00 10 91 fd fa 59 07 |..............Y.| +00000050 df 2c 92 25 15 7b 7c 83 44 89 0d 4f 65 43 99 2e |.,.%.{|.D..OeC..| +00000060 41 5d 51 c9 09 89 ed 02 08 bc |A]Q.......| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 index 8483870fe83..f7be3f7e93a 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 02 00 51 02 00 00 4d 03 02 52 cc 57 58 d2 |....Q...M..R.WX.| -00000010 3e 7a 93 49 2a f2 3f f8 fe 58 6b 88 d2 87 66 71 |>z.I*.?..Xk...fq| -00000020 69 bd d2 98 03 4b 17 b1 5d 5b a5 20 c6 5d a6 c7 |i....K..][. .]..| -00000030 40 53 b8 4f 68 74 12 70 64 58 4f 78 fa d1 a9 5c |@S.Oht.pdXOx...\| -00000040 f0 ce 5e 78 fd 66 30 98 8e ac 94 37 00 05 00 00 |..^x.f0....7....| +00000000 16 03 02 00 51 02 00 00 4d 03 02 53 04 f1 02 d4 |....Q...M..S....| +00000010 69 65 aa 96 3d 42 96 eb 9e 7d 8a 18 af 4c 7c 5d |ie..=B...}...L|]| +00000020 fb 97 5f da 94 62 13 69 1f 66 06 20 aa 52 e3 08 |.._..b.i.f. .R..| +00000030 35 0a 87 d5 ef 93 49 ab 1a 74 dd 90 bd 69 70 d1 |5.....I..t...ip.| +00000040 e9 f1 44 17 3a dc 33 98 f5 e5 ab 93 00 05 00 00 |..D.:.3.........| 00000050 05 ff 01 00 01 00 16 03 02 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -69,15 +69,15 @@ 00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 02 00 01 |5..C.0oUN.p.....| -00000090 01 16 03 02 00 24 6c 69 1d 96 27 2b f5 0b 6e d5 |.....$li..'+..n.| -000000a0 f7 97 96 c6 9f 5e 59 92 9f 3a 0e e5 d0 36 e4 af |.....^Y..:...6..| -000000b0 bc 17 bf 95 ab f7 0c 19 a6 86 |..........| +00000090 01 16 03 02 00 24 07 9f dc df 2d c3 a6 88 06 28 |.....$....-....(| +000000a0 21 e0 e0 d3 31 99 fc 89 b8 82 6e 95 f4 4b 9e e2 |!...1.....n..K..| +000000b0 d9 36 5c 14 ce d7 db e2 78 4e |.6\.....xN| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 24 dd 9f e5 d3 53 |..........$....S| -00000010 ae af f2 41 bf eb 53 33 71 d0 f3 84 ac b0 88 72 |...A..S3q......r| -00000020 2d de 14 5b 59 9d f3 4c 9f ab a1 aa f4 f3 af |-..[Y..L.......| +00000000 14 03 02 00 01 01 16 03 02 00 24 81 72 75 80 d4 |..........$.ru..| +00000010 1b 1a 32 00 89 bf 9e 79 30 b9 6b 67 e0 8e c7 eb |..2....y0.kg....| +00000020 73 f2 e4 93 51 65 9b 5f 91 b1 b4 b1 f7 44 76 |s...Qe._.....Dv| >>> Flow 5 (client to server) -00000000 17 03 02 00 1a 24 4d 6b 23 8a 36 07 80 49 1a e5 |.....$Mk#.6..I..| -00000010 da 85 7c a0 cb f3 82 e5 23 d7 b9 46 82 cb bc 15 |..|.....#..F....| -00000020 03 02 00 16 f3 f1 5b f2 40 0f 3f 88 ea f2 4e 28 |......[.@.?...N(| -00000030 52 aa c6 3a 6c 88 e3 30 21 0f |R..:l..0!.| +00000000 17 03 02 00 1a b2 91 39 63 c0 38 3c 4d 25 fd 14 |.......9c.8<M%..| +00000010 b9 b6 e1 23 21 b4 8d 17 9e 1f d8 33 92 69 c2 15 |...#!......3.i..| +00000020 03 02 00 16 4b 10 25 4d 9d 09 c2 11 96 be f7 5b |....K.%M.......[| +00000030 c2 9b 99 fd 1f 8e af 0f 2c 51 |........,Q| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA index 0731ee2c35b..20732703647 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 52 cc 57 59 76 |....Y...U..R.WYv| -00000010 bc 07 88 2c 89 e3 aa 41 69 76 d1 0b 5f c0 7a b1 |...,...Aiv.._.z.| -00000020 c3 c4 f8 12 6e 73 7f 5b 25 41 8e 20 b4 2d 8d a9 |....ns.[%A. .-..| -00000030 80 95 44 d4 d7 47 8c a1 f1 de 36 57 cf 54 dd ee |..D..G....6W.T..| -00000040 a7 d8 ba cf ca b7 68 0e 9e b4 a3 7b c0 09 00 00 |......h....{....| +00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 03 6f |....Y...U..S...o| +00000010 c6 4b 55 27 fe e8 fe 4d 7c 0e d4 20 98 b8 7c 81 |.KU'...M|.. ..|.| +00000020 3d 31 f8 35 66 2f 0a 0b f1 2c e3 20 86 4d 12 32 |=1.5f/...,. .M.2| +00000030 73 e3 ba be 25 50 a4 a2 a1 7b f1 9a 76 7a 75 fb |s...%P...{..vzu.| +00000040 e2 64 a2 12 ec f3 e7 9d 9a 24 6e 94 c0 09 00 00 |.d.......$n.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,24 +47,24 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 3a |*............A.:| -00000280 16 95 9a af 75 ff 51 27 76 6e 82 c7 db a2 3d 62 |....u.Q'vn....=b| -00000290 b4 65 d1 97 26 38 55 68 29 68 2c fc 4b 69 2c f9 |.e..&8Uh)h,.Ki,.| -000002a0 01 00 4b 1e ee cf 88 54 a7 f3 49 a5 04 98 bd 12 |..K....T..I.....| -000002b0 74 b1 cb 95 4c 49 c2 1a 31 e6 95 9f f5 0a f5 04 |t...LI..1.......| -000002c0 03 00 8b 30 81 88 02 42 01 e7 72 2b 54 9e e0 97 |...0...B..r+T...| -000002d0 79 e6 23 52 f7 2e 08 36 d5 dc 31 21 9d f2 13 ae |y.#R...6..1!....| -000002e0 30 86 1c df d2 be 52 e0 e7 8b f5 dd fa 09 f2 f3 |0.....R.........| -000002f0 97 5d f7 48 37 83 9b aa 6c ef 87 95 de f4 50 19 |.].H7...l.....P.| -00000300 b2 9b d6 27 4c 4d 67 6a 27 be 02 42 01 d8 86 63 |...'LMgj'..B...c| -00000310 dc f1 9f 32 a3 25 6f 55 b3 67 7b 64 7e 24 38 25 |...2.%oU.g{d~$8%| -00000320 96 bb 7b b1 9b ef 73 c3 6c d1 69 83 7d bc c5 30 |..{...s.l.i.}..0| -00000330 fe 9a 21 0d 29 c4 d6 1a 51 a5 dd 6e a0 80 c8 9c |..!.)...Q..n....| -00000340 54 49 34 22 f7 5e cf 28 ae 2f cd 46 b1 71 16 03 |TI4".^.(./.F.q..| -00000350 03 00 30 0d 00 00 28 03 01 02 40 00 20 06 01 06 |..0...(...@. ...| -00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| -00000370 01 03 02 03 03 02 01 02 02 02 03 01 01 00 00 0e |................| -00000380 00 00 00 |...| +00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 a3 |*............A..| +00000280 03 8c de d2 b0 68 c8 25 0e 85 ea d7 ae 13 0d 79 |.....h.%.......y| +00000290 ec 59 0d b5 4d 51 96 d9 7f 64 36 fb 4c d5 6a 26 |.Y..MQ...d6.L.j&| +000002a0 ae 0e 48 61 df 5c 2b d4 ff 09 41 15 c4 14 8e 1b |..Ha.\+...A.....| +000002b0 84 a8 c8 cd ef 10 97 95 66 67 85 dd fd dc 2a 04 |........fg....*.| +000002c0 03 00 8a 30 81 87 02 41 11 75 5d bc bd 08 28 d4 |...0...A.u]...(.| +000002d0 5b 1b 45 7f 9c d3 8d 0b 91 fa f6 82 ba 59 bd 3e |[.E..........Y.>| +000002e0 96 01 c6 1d 38 db fe 08 e7 56 89 fc 10 b0 37 6a |....8....V....7j| +000002f0 3d d6 c9 50 16 53 f7 c2 a2 60 67 82 1f 74 b8 d5 |=..P.S...`g..t..| +00000300 bc 02 ec 96 db 82 18 8c 87 02 42 01 0d df f7 b7 |..........B.....| +00000310 05 3c 8c 56 f0 1d 33 18 cf c5 4c 80 7e 0b d9 f9 |.<.V..3...L.~...| +00000320 f0 51 69 fe 5d b8 0b 64 c0 c7 0d f4 75 65 ae 07 |.Qi.]..d....ue..| +00000330 9d cf f4 4b ad 52 f6 b8 10 26 18 bd d6 e2 0d a8 |...K.R...&......| +00000340 80 10 50 34 15 cd 72 0b 7d a9 94 de 4c 16 03 03 |..P4..r.}...L...| +00000350 00 30 0d 00 00 28 03 01 02 40 00 20 06 01 06 02 |.0...(...@. ....| +00000360 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| +00000370 03 02 03 03 02 01 02 02 02 03 01 01 00 00 0e 00 |................| +00000380 00 00 |..| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| @@ -111,24 +111,24 @@ 000002a0 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 |...jB..~~1...f.A| 000002b0 4b 49 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 |KI.......P.m..Q.| 000002c0 c0 ab 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 |.....>K.S:.e....| -000002d0 88 a6 56 bf d0 53 0b a9 7e 82 7d 4d fc 66 78 8f |..V..S..~.}M.fx.| -000002e0 57 dc 5e 62 54 70 cc 32 0c 1c b5 62 fc 6a 76 7e |W.^bTp.2...b.jv~| -000002f0 3f 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |?..........@....| -00000300 00 00 00 00 00 00 00 00 00 00 00 00 62 a7 74 42 |............b.tB| -00000310 ab 04 f8 f9 5a 86 3e 35 94 ce 4b 79 77 a1 a0 6a |....Z.>5..Kyw..j| -00000320 cf 2b 3a 62 fc 3b 50 2b 51 5e d7 6a d1 d0 65 b4 |.+:b.;P+Q^.j..e.| -00000330 5d 15 99 11 10 d3 6b a3 97 d2 30 08 |].....k...0.| +000002d0 88 0d 64 db 8e 4f 73 4e ea 29 0b ed a0 f5 ce 3d |..d..OsN.).....=| +000002e0 5f cc 20 ef 0a 22 02 82 f2 14 2a b7 42 68 bd c7 |_. .."....*.Bh..| +000002f0 4d 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |M..........@....| +00000300 00 00 00 00 00 00 00 00 00 00 00 00 f0 cc 4f c7 |..............O.| +00000310 b6 0f c9 38 4d 4b 97 2c 4f be 53 08 4c d6 5b 4e |...8MK.,O.S.L.[N| +00000320 24 70 30 81 82 3a 7f 62 95 03 4d fc 54 78 ec 13 |$p0..:.b..M.Tx..| +00000330 b2 a1 00 85 2b 04 e4 1d 7b 6e 87 60 |....+...{n.`| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 fa 8c c0 6f 59 |..........@...oY| -00000010 8f af a8 21 c8 aa 4c 00 db 6a a5 98 09 52 1a 27 |...!..L..j...R.'| -00000020 77 af 6d 13 c2 54 f8 90 31 37 5c 86 3b 66 de d8 |w.m..T..17\.;f..| -00000030 41 96 8b 84 d9 75 c0 00 b5 5f 99 3e a9 19 fa 6b |A....u..._.>...k| -00000040 be e2 78 43 30 41 94 39 ce 87 67 |..xC0A.9..g| +00000000 14 03 03 00 01 01 16 03 03 00 40 d5 2a 76 79 1c |..........@.*vy.| +00000010 e7 d5 b1 5c 65 6b d1 45 73 53 4c 05 3a 6c 5d 81 |...\ek.EsSL.:l].| +00000020 dd 2f f0 74 62 e4 8e f8 ed 21 99 c7 4f d6 28 40 |./.tb....!..O.(@| +00000030 63 d9 6d e5 b0 04 73 27 7a 1d 08 19 31 10 da ef |c.m...s'z...1...| +00000040 79 26 33 fb 45 23 be a4 7c 03 66 |y&3.E#..|.f| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 76 8b 21 f2 c9 fe b7 c4 60 e6 91 |.....v.!.....`..| -00000020 00 ca 3e 54 25 5e f4 20 f8 df 58 41 03 b0 d0 fb |..>T%^. ..XA....| -00000030 e7 59 4d 6a 34 15 03 03 00 30 00 00 00 00 00 00 |.YMj4....0......| -00000040 00 00 00 00 00 00 00 00 00 00 0f 0f e5 7a a2 86 |.............z..| -00000050 8c 31 53 05 be 22 fb 53 51 e6 26 0a a5 c5 09 ca |.1S..".SQ.&.....| -00000060 f3 46 0f 67 50 d8 83 35 7b f3 |.F.gP..5{.| +00000010 00 00 00 00 00 e2 53 bd c0 ef 9e e6 44 94 ea 5d |......S.....D..]| +00000020 f5 c5 a9 4b ed eb 1c 49 9f 79 44 f9 cd d7 de 02 |...K...I.yD.....| +00000030 51 10 ae 87 7d 15 03 03 00 30 00 00 00 00 00 00 |Q...}....0......| +00000040 00 00 00 00 00 00 00 00 00 00 d3 95 13 7f 5f 58 |.............._X| +00000050 ab d6 17 ea 01 2c 2a ea 5d 7c 44 61 4a 27 97 52 |.....,*.]|DaJ'.R| +00000060 cc 9b 86 f6 37 42 2b 94 01 49 |....7B+..I| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA index 9edab394f70..c3b753a7b44 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 52 cc 57 59 85 |....Q...M..R.WY.| -00000010 0f 00 df b8 0d ef c4 98 ba e3 bd 71 4c 98 e5 80 |...........qL...| -00000020 af 77 c7 d8 5f c1 36 62 1c ef 89 20 b6 01 c3 3b |.w.._.6b... ...;| -00000030 9e 93 27 04 05 7b 73 b3 02 7b c3 89 f5 ac 51 24 |..'..{s..{....Q$| -00000040 7c e5 6d f3 34 d0 99 71 5e ae 30 ea 00 05 00 00 ||.m.4..q^.0.....| +00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 03 b0 |....Q...M..S....| +00000010 43 00 97 24 a7 a8 ea b2 24 fe 96 24 a1 49 64 fd |C..$....$..$.Id.| +00000020 1c a3 30 35 2d 85 a7 40 42 86 6b 20 af 27 7f ac |..05-..@B.k .'..| +00000030 8b 16 89 6c 78 b7 f5 29 02 58 a6 8b 61 43 c2 b0 |...lx..).X..aC..| +00000040 e0 a8 96 c8 fa 2b 26 ad 9a 5f 2d d6 00 05 00 00 |.....+&.._-.....| 00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -111,17 +111,17 @@ 000002e0 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 |...jB..~~1...f.A| 000002f0 4b 49 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 |KI.......P.m..Q.| 00000300 c0 ab 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 |.....>K.S:.e....| -00000310 88 d6 42 09 8f e0 57 a7 e6 9e 65 3d fd 82 45 9d |..B...W...e=..E.| -00000320 3e 69 cc ad 17 72 c7 98 8d 3a ca f0 05 63 43 40 |>i...r...:...cC@| -00000330 7a 14 03 03 00 01 01 16 03 03 00 24 a8 45 b8 6e |z..........$.E.n| -00000340 21 28 b3 6d 94 0d 7b c4 af 24 0e ca 51 ec 85 3c |!(.m..{..$..Q..<| -00000350 87 43 fd 36 e4 3d 1a f4 28 df 90 19 b6 05 d0 c9 |.C.6.=..(.......| +00000310 88 5a 97 82 3e 55 6b 7c d8 db b8 cc 1b 30 84 0a |.Z..>Uk|.....0..| +00000320 7a 97 71 e4 10 bb a4 39 8c 2a cf f5 88 c7 d1 95 |z.q....9.*......| +00000330 73 14 03 03 00 01 01 16 03 03 00 24 9f 1e f0 72 |s..........$...r| +00000340 92 ea dc f7 56 96 37 e4 69 db db 66 1d f6 94 c4 |....V.7.i..f....| +00000350 18 31 4f d0 5d c5 f4 53 21 aa 98 b1 dc 08 94 94 |.1O.]..S!.......| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 ae 0d d7 72 4f |..........$...rO| -00000010 70 d9 16 20 da 70 dd 04 d5 5a 96 32 80 8c 14 db |p.. .p...Z.2....| -00000020 4d 10 31 47 1e 26 78 f1 95 25 0c fe 24 2f 6f |M.1G.&x..%..$/o| +00000000 14 03 03 00 01 01 16 03 03 00 24 ee 68 c1 87 9f |..........$.h...| +00000010 d7 90 94 f1 3b 6d 26 0b 3d 89 7a 45 3b 52 5d 3c |....;m&.=.zE;R]<| +00000020 dd 7c c1 4e 57 3e a9 ee 91 be cf 2b a3 98 9d |.|.NW>.....+...| >>> Flow 5 (client to server) -00000000 17 03 03 00 1a d4 7d c7 83 f7 98 3b 77 91 4b e6 |......}....;w.K.| -00000010 68 fa e2 22 37 24 93 20 fa e2 67 18 03 41 90 15 |h.."7$. ..g..A..| -00000020 03 03 00 16 0b ff 73 1c e5 81 5f 28 52 72 49 39 |......s..._(RrI9| -00000030 ca 42 fb 57 8a 3a 80 75 2b ac |.B.W.:.u+.| +00000000 17 03 03 00 1a 88 33 3e 2b 22 6b 92 d0 bb 8a 1e |......3>+"k.....| +00000010 9b f4 9e aa 91 8b 2b 95 ea 53 c8 03 0a 93 58 15 |......+..S....X.| +00000020 03 03 00 16 c4 67 79 ba ec cf 90 b1 f9 ac ec 64 |.....gy........d| +00000030 72 01 08 8f 3a 98 aa 66 25 00 |r...:..f%.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA index 2b380a8119f..0037af61a03 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 52 cc 57 58 6a |....Y...U..R.WXj| -00000010 f6 51 de a7 6b b0 94 bb 98 24 ab e2 c0 02 e4 8c |.Q..k....$......| -00000020 ac a8 48 5d 41 82 eb c0 de 5a 1e 20 70 29 82 6c |..H]A....Z. p).l| -00000030 01 cf 4e 21 52 18 98 8c 0a 31 14 26 6c a4 44 11 |..N!R....1.&l.D.| -00000040 6c 5b d6 5c cb a4 b1 91 52 13 b5 77 c0 09 00 00 |l[.\....R..w....| +00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 fd |....Y...U..S....| +00000010 41 bd ef ee f3 da fc 1a 31 8c 77 f2 e9 66 54 a0 |A.......1.w..fT.| +00000020 f4 15 b1 1c 84 0d 6d 74 87 ac 7d 20 78 17 8b 08 |......mt..} x...| +00000030 10 20 c9 44 e4 8a 43 af 4a c7 b8 3d 99 f2 f7 af |. .D..C.J..=....| +00000040 bb a3 21 2f 40 cc ed b6 da a8 a1 d5 c0 09 00 00 |..!/@...........| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,20 +47,20 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 de |*............A..| -00000280 c7 75 51 96 25 63 8e c0 da 9c c0 8e d1 76 ca 08 |.uQ.%c.......v..| -00000290 4c f5 a0 13 75 01 ab cf 12 09 ae cd 13 53 84 1e |L...u........S..| -000002a0 a4 f8 46 0f 15 08 18 48 65 d9 75 85 80 38 79 b7 |..F....He.u..8y.| -000002b0 fc 51 a2 7c 7a ac ab b9 67 8a d7 16 af 75 df 04 |.Q.|z...g....u..| -000002c0 03 00 8b 30 81 88 02 42 00 fe 19 74 a9 a1 27 05 |...0...B...t..'.| -000002d0 92 78 a4 c8 9d c8 a5 de 67 cd 1f a3 1b c7 ba 7e |.x......g......~| -000002e0 75 68 15 29 16 e7 91 f9 b9 7b d7 e4 e9 c0 2a 7f |uh.).....{....*.| -000002f0 1a ce 71 5a b9 c1 64 dd 26 59 24 e8 34 21 24 8a |..qZ..d.&Y$.4!$.| -00000300 b0 19 06 d4 46 0c 05 46 dc 5f 02 42 00 a8 05 71 |....F..F._.B...q| -00000310 59 ef 60 fa cf 06 ec 18 5f be 53 b7 95 07 05 5b |Y.`....._.S....[| -00000320 70 87 ac da f4 61 94 41 60 c8 ab 7b 26 5a 32 4d |p....a.A`..{&Z2M| -00000330 0d 53 00 0e 8e b3 b2 16 c7 4e 3a 15 14 76 bc dc |.S.......N:..v..| -00000340 ff b6 60 eb 62 b6 15 34 53 4f 2a 42 48 2c 16 03 |..`.b..4SO*BH,..| +00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 a9 |*............A..| +00000280 19 8b d9 9b 5c 7c 6a 7d 85 d2 70 4e 89 7e 0b 5b |....\|j}..pN.~.[| +00000290 dd 5e a1 63 8d 15 bc 0b 0c 47 3d 4d e8 a7 56 88 |.^.c.....G=M..V.| +000002a0 2e f6 7f e2 4d fc ed cc 03 ed a1 2d ac ae 81 a5 |....M......-....| +000002b0 e2 6d 7f 9f a3 93 e9 10 c1 0e 48 1b f3 f4 38 04 |.m........H...8.| +000002c0 03 00 8b 30 81 88 02 42 00 87 fe 7e 63 82 14 57 |...0...B...~c..W| +000002d0 dc 7d e2 0f cc 97 2d ba 3c a7 56 4a 17 a8 09 6a |.}....-.<.VJ...j| +000002e0 28 2e f2 66 1a 3f 2d 48 2b 6f 79 a1 60 cd 5e 10 |(..f.?-H+oy.`.^.| +000002f0 0b 0a 28 f2 5f e4 3f 4f f9 c9 91 34 d9 dc bc fc |..(._.?O...4....| +00000300 98 ea 77 0b 99 f8 a2 11 c4 bd 02 42 01 a0 b0 dc |..w........B....| +00000310 db 5b c2 09 99 bd ee a0 b9 aa 31 b9 10 84 22 be |.[........1...".| +00000320 5a 63 12 5a 43 00 8e c1 33 cc 91 bb c2 70 7a 63 |Zc.ZC...3....pzc| +00000330 19 82 c0 74 48 a1 c7 3d 1f f1 6f 4a 6f 6a 8c 3f |...tH..=..oJoj.?| +00000340 28 31 a8 0c 65 19 26 62 4b 7a 7c 4b ea 1a 16 03 |(1..e.&bKz|K....| 00000350 03 00 30 0d 00 00 28 03 01 02 40 00 20 06 01 06 |..0...(...@. ...| 00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| 00000370 01 03 02 03 03 02 01 02 02 02 03 01 01 00 00 0e |................| @@ -103,31 +103,31 @@ 00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......| -00000250 0f 00 00 84 04 01 00 80 42 bd a6 a2 1f 49 ea 57 |........B....I.W| -00000260 43 59 a0 b6 9f 1d b3 3c 35 a7 fa c7 57 02 fa f0 |CY.....<5...W...| -00000270 9f 7d a2 77 1a a4 e1 13 c0 78 a3 9e 59 1a f2 c6 |.}.w.....x..Y...| -00000280 2b dd 8d bc 5d f1 99 e8 db ac a2 9c 6e d8 b5 6a |+...].......n..j| -00000290 a5 04 aa 6c 48 b8 7a 06 55 81 1a e0 41 69 28 42 |...lH.z.U...Ai(B| -000002a0 53 fa f0 63 a9 b5 c1 2f 69 60 cf 02 da d2 eb c8 |S..c.../i`......| -000002b0 e8 a1 5c 7b b1 05 c3 b8 66 34 fe 21 8a 7a 84 10 |..\{....f4.!.z..| -000002c0 f1 4d bd b1 68 97 85 11 10 bf be 96 cf 37 e9 68 |.M..h........7.h| -000002d0 20 ab d2 f8 d2 20 65 90 14 03 03 00 01 01 16 03 | .... e.........| +00000250 0f 00 00 84 04 01 00 80 38 f2 16 e5 b5 86 16 62 |........8......b| +00000260 86 e1 7d 01 f1 a8 e1 f7 e7 85 b1 a0 17 ee 84 25 |..}............%| +00000270 cb 3c 46 61 1a 78 7b 1e ee 32 bc d9 6c fa 6b 76 |.<Fa.x{..2..l.kv| +00000280 67 a7 9e c8 7a 4c e8 79 0d 22 27 ad e7 98 6a 98 |g...zL.y."'...j.| +00000290 89 88 8b a9 69 5b 6f c6 00 48 9a 21 77 a9 7c 15 |....i[o..H.!w.|.| +000002a0 ba 47 16 74 8d 6c 67 dc 6d f1 98 b6 61 e8 bc 08 |.G.t.lg.m...a...| +000002b0 18 53 a6 93 bf fc 27 5e b7 4d d2 eb 68 e9 23 ee |.S....'^.M..h.#.| +000002c0 d2 70 d2 55 2c c7 99 7d c0 66 b5 1c ea 38 71 5c |.p.U,..}.f...8q\| +000002d0 a6 57 1f 52 e4 8e e8 51 14 03 03 00 01 01 16 03 |.W.R...Q........| 000002e0 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 |..@.............| -000002f0 00 00 00 a1 73 35 05 15 f3 87 00 58 06 54 f7 44 |....s5.....X.T.D| -00000300 25 71 3f a6 16 3c e9 95 0a de 14 9d d0 78 73 35 |%q?..<.......xs5| -00000310 a4 84 dc 9e bf 94 4e fe 07 89 33 d0 81 ef 9f 49 |......N...3....I| -00000320 17 0a 64 |..d| +000002f0 00 00 00 5e e7 6e 1c a2 02 24 34 f0 a6 b6 27 ea |...^.n...$4...'.| +00000300 69 d5 0e 2e a8 ad 5c ad 6c 06 78 68 39 92 27 f1 |i.....\.l.xh9.'.| +00000310 e8 35 49 67 4d fb 5d 8a 31 2e 4e 3f 19 ed ea 30 |.5IgM.].1.N?...0| +00000320 20 60 e1 | `.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 19 b8 9d de 48 |..........@....H| -00000010 86 1e be b4 62 54 57 12 fc f0 ad fd 70 b7 69 48 |....bTW.....p.iH| -00000020 58 66 8e 68 1c fd 73 62 da bd 6d 8f 83 8c 09 91 |Xf.h..sb..m.....| -00000030 de 53 83 20 2b 81 f1 30 3f 0b 6b 7d c1 59 47 dc |.S. +..0?.k}.YG.| -00000040 e1 f4 95 85 d5 0b 09 45 4e a7 2f |.......EN./| +00000000 14 03 03 00 01 01 16 03 03 00 40 ee a8 82 bc 3f |..........@....?| +00000010 bf ab a6 e4 30 e0 3d f1 2f 19 a2 ac 7a 81 57 f1 |....0.=./...z.W.| +00000020 ee 67 3f 55 2b 30 fa 72 b5 10 03 ec 8d 0a 8f bb |.g?U+0.r........| +00000030 24 f5 45 f5 4e 53 4b 93 a5 0d 42 6c 46 69 98 fb |$.E.NSK...BlFi..| +00000040 63 c5 9f 95 65 d1 b6 f0 a4 15 bd |c...e......| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 69 73 64 71 d8 dc 9b a5 ce 9a 1e |.....isdq.......| -00000020 65 82 01 94 45 12 e7 13 4e 3e 59 7b 19 2b 41 a7 |e...E...N>Y{.+A.| -00000030 49 aa 70 1d ce 15 03 03 00 30 00 00 00 00 00 00 |I.p......0......| -00000040 00 00 00 00 00 00 00 00 00 00 5f 67 8d e3 77 5e |.........._g..w^| -00000050 32 c4 83 91 2b e6 37 76 18 11 8d 9f e5 c2 20 43 |2...+.7v...... C| -00000060 c1 68 83 f9 e6 0b 07 95 ef b6 |.h........| +00000010 00 00 00 00 00 cb 4e bc d1 a9 58 ef c8 39 a9 36 |......N...X..9.6| +00000020 f4 35 05 96 8e a4 50 bc f4 15 06 f9 fd 41 6d 1e |.5....P......Am.| +00000030 5e 7c 82 63 94 15 03 03 00 30 00 00 00 00 00 00 |^|.c.....0......| +00000040 00 00 00 00 00 00 00 00 00 00 bd 77 87 a5 5a d4 |...........w..Z.| +00000050 b8 59 e6 6b 0f dd ea f9 ed 18 b2 9f a9 61 b4 3a |.Y.k.........a.:| +00000060 47 15 15 3b 83 ef e1 6d db a8 |G..;...m..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA index dc56555cf1d..df3eaa4406e 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 52 cc 57 58 8f |....Q...M..R.WX.| -00000010 4b 2e 8c 90 dd 88 33 43 44 02 90 c0 b5 ae b3 b2 |K.....3CD.......| -00000020 c9 2c cd c4 53 8e 7e 5c de 08 fe 20 ee 4e 7b b1 |.,..S.~\... .N{.| -00000030 7e a2 eb b0 21 e3 b2 1e b5 18 ff b3 43 c8 a7 a3 |~...!.......C...| -00000040 2f ef 82 11 ae 66 be c5 64 5d 15 59 00 05 00 00 |/....f..d].Y....| +00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 02 1d |....Q...M..S....| +00000010 0e dc 86 e5 a9 07 71 46 15 34 af 47 15 3f 03 9c |......qF.4.G.?..| +00000020 fc d6 fd 44 7c f4 f1 c7 8d 6f f8 20 28 ea 3c dc |...D|....o. (.<.| +00000030 b2 4c b7 ba 20 88 c4 db a5 73 ea 93 ab 3a 85 a6 |.L.. ....s...:..| +00000040 8f 59 49 d9 a9 31 14 d5 a6 2b 4f d1 00 05 00 00 |.YI..1...+O.....| 00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -103,24 +103,24 @@ 00000260 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000270 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000280 35 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 03 00 88 |5..C.0oUN.p.....| -00000290 0f 00 00 84 04 01 00 80 0a eb 78 3e 77 c5 9c 8e |..........x>w...| -000002a0 05 67 4e 06 bd ec c8 7c b2 16 13 7d c5 5d e1 1a |.gN....|...}.]..| -000002b0 4d 2e f4 b1 78 2c 94 1b 47 e4 3e 2f 7e 74 cc 03 |M...x,..G.>/~t..| -000002c0 1d eb e2 56 99 0e 92 27 79 e4 7e a7 12 86 88 91 |...V...'y.~.....| -000002d0 a4 99 db 1d 50 62 88 41 cc a6 b7 90 d0 51 66 47 |....Pb.A.....QfG| -000002e0 92 39 a0 2b 4c 8d 50 a6 af f4 72 2d 16 3b 6b b8 |.9.+L.P...r-.;k.| -000002f0 82 d2 9a d8 cd 7b b9 aa 82 a5 31 12 9e bb 19 23 |.....{....1....#| -00000300 15 5d ad a5 b1 65 c1 de 01 7d e3 d3 16 73 28 d6 |.]...e...}...s(.| -00000310 75 02 32 68 5a e0 b1 bb 14 03 03 00 01 01 16 03 |u.2hZ...........| -00000320 03 00 24 cd c6 25 df 1c 0b b3 a7 2a 46 99 b8 10 |..$..%.....*F...| -00000330 37 78 40 2a aa 66 7a 3a 34 8e 87 bf 85 4c e2 de |7x@*.fz:4....L..| -00000340 36 62 4a 9e 7f e8 e8 |6bJ....| +00000290 0f 00 00 84 04 01 00 80 2a 1f ae 48 9f 86 16 dc |........*..H....| +000002a0 c2 55 1f 5f 95 81 ed 56 00 5d 35 46 e5 b6 57 d5 |.U._...V.]5F..W.| +000002b0 a6 3e 32 38 8b e2 c6 1c b9 b1 38 b2 da 66 45 ed |.>28......8..fE.| +000002c0 58 6a 7f 43 41 93 a5 09 da b9 04 ce 3f 13 8a 19 |Xj.CA.......?...| +000002d0 13 e9 2c 1f c5 e7 35 b4 2d ea 7c 81 90 33 c0 66 |..,...5.-.|..3.f| +000002e0 dc 41 8b 23 08 8f 69 d4 d6 a2 5f c1 bd 26 e6 2e |.A.#..i..._..&..| +000002f0 7f c8 7c a8 2d d4 08 95 ce 6e 58 54 04 a2 a6 63 |..|.-....nXT...c| +00000300 54 72 67 f2 7f 61 0a 6b 58 46 d4 88 95 38 37 f2 |Trg..a.kXF...87.| +00000310 93 95 48 56 14 a7 b9 7c 14 03 03 00 01 01 16 03 |..HV...|........| +00000320 03 00 24 64 bb 41 3a cb a2 2f 95 53 5c 2f f7 83 |..$d.A:../.S\/..| +00000330 a2 35 18 f6 d0 8d 6f e2 54 ed 2f 07 10 f4 36 e2 |.5....o.T./...6.| +00000340 3d e5 30 1d e3 63 01 |=.0..c.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 20 68 ec 6b 11 |..........$ h.k.| -00000010 e5 d6 eb c7 4f 7f e0 d0 c4 36 d4 c2 46 06 1d 92 |....O....6..F...| -00000020 83 b4 77 e2 58 b6 cb 06 74 0a 5c f8 c6 06 83 |..w.X...t.\....| +00000000 14 03 03 00 01 01 16 03 03 00 24 0a 22 b6 bc da |..........$."...| +00000010 34 38 53 8e 80 e2 25 7b 31 2f 70 8e 3a db e8 a3 |48S...%{1/p.:...| +00000020 70 0e 88 22 b4 a8 be d4 a3 e3 cc 13 94 ef 47 |p.."..........G| >>> Flow 5 (client to server) -00000000 17 03 03 00 1a bb d6 71 f3 e0 2f c3 d6 0d 70 85 |.......q../...p.| -00000010 25 df 6f ba b1 37 dd 49 42 79 5c b3 c1 85 7e 15 |%.o..7.IBy\...~.| -00000020 03 03 00 16 8c 93 50 30 45 38 da e2 bf c6 df d8 |......P0E8......| -00000030 41 e1 63 ca 28 82 d1 ae 30 76 |A.c.(...0v| +00000000 17 03 03 00 1a b4 9c b1 57 ea 01 03 fe 01 e7 1e |........W.......| +00000010 c4 a7 0f 25 14 99 00 4f 88 51 c1 98 6e 99 01 15 |...%...O.Q..n...| +00000020 03 03 00 16 2e c4 11 8b 1a fc 37 81 18 33 e4 9f |..........7..3..| +00000030 48 a3 29 e3 ad 9b 9b ec 9f 99 |H.).......| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES index 47bbebfc457..76445903bac 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 52 cc 57 58 4e |....Y...U..R.WXN| -00000010 9d 88 aa 42 ea 19 04 55 fe e8 13 0c db 2d a9 70 |...B...U.....-.p| -00000020 93 85 12 08 d2 15 f6 61 25 84 b7 20 55 a3 15 3b |.......a%.. U..;| -00000030 27 48 55 53 d1 23 c5 e8 f4 83 ce 44 db 2c 47 b8 |'HUS.#.....D.,G.| -00000040 2b 4a 3e be 29 3d 73 76 dc 79 6b 75 c0 09 00 00 |+J>.)=sv.yku....| +00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 a0 |....Y...U..S....| +00000010 5f bd a4 8d 98 93 b8 da 08 86 9f b2 be 9a a4 91 |_...............| +00000020 2b 3c 1f 18 f0 75 7c a9 a8 a0 f7 20 4a 89 9a d2 |+<...u|.... J...| +00000030 34 3b d9 b1 c2 fd 61 bd 97 19 22 ce b9 d1 5b a7 |4;....a..."...[.| +00000040 83 80 9c 19 d0 f5 a0 aa 4c ac 06 20 c0 09 00 00 |........L.. ....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,21 +47,21 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 67 |*............A.g| -00000280 9e b0 72 cf 69 da 56 8c d2 8f fb 80 64 bb d2 ec |..r.i.V.....d...| -00000290 57 2d 8c 77 b7 5a b5 bc ae bb 1f de db e7 64 5c |W-.w.Z........d\| -000002a0 36 2a 9b cb 92 a7 f1 db 93 76 8c 10 b5 74 ad b5 |6*.......v...t..| -000002b0 8f c5 79 18 18 e7 92 6f 22 3b 92 47 dc 60 cf 04 |..y....o";.G.`..| -000002c0 03 00 8b 30 81 88 02 42 01 c9 0b bf 07 18 e3 7d |...0...B.......}| -000002d0 26 b0 17 94 70 1d dc e8 6c 9e 45 4f d5 e0 79 00 |&...p...l.EO..y.| -000002e0 2b 03 90 bb 7a aa 23 01 43 53 a1 d8 9f 81 1f 18 |+...z.#.CS......| -000002f0 a2 5f 54 fa 7c c3 3a 15 d4 18 38 80 7e de f0 70 |._T.|.:...8.~..p| -00000300 42 5d 2a 22 74 d1 6c 75 f5 18 02 42 00 a8 0a 3c |B]*"t.lu...B...<| -00000310 44 38 fa 3f b7 fc 00 1e 80 30 0d e5 55 87 99 53 |D8.?.....0..U..S| -00000320 0a ab cd ad dd 1b 72 7f 49 bf 2f 89 74 72 11 3c |......r.I./.tr.<| -00000330 6e 49 5e 31 3c 6c f1 bc 90 fc e9 75 95 78 7b 95 |nI^1<l.....u.x{.| -00000340 6a 8d 4d 51 0f e1 2f d1 9e 7b b7 c1 aa 62 16 03 |j.MQ../..{...b..| -00000350 03 00 04 0e 00 00 00 |.......| +00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 3c |*............A.<| +00000280 8f 35 1e 47 5d 7b ad 13 0c e9 5c c0 97 c7 83 06 |.5.G]{....\.....| +00000290 49 0f 6c cf e5 4d 3b ed f7 1b c6 96 8d ba 54 35 |I.l..M;.......T5| +000002a0 7f df 35 e3 6e 28 e9 71 f2 24 b5 ab 17 2b 4b 2b |..5.n(.q.$...+K+| +000002b0 0c 8f 9f 48 89 73 8f 09 69 84 af 7f ec 43 7a 04 |...H.s..i....Cz.| +000002c0 03 00 8a 30 81 87 02 41 79 84 43 0c 78 fa 7e e2 |...0...Ay.C.x.~.| +000002d0 c5 51 c1 60 88 c4 4a 59 7d 02 fa dc 19 68 33 ed |.Q.`..JY}....h3.| +000002e0 19 ef a1 df ef 6b 21 a6 98 aa ba a9 13 70 91 0f |.....k!......p..| +000002f0 cc 6c 5c 1e 99 53 1b 42 51 6c 06 a7 3c c4 04 22 |.l\..S.BQl..<.."| +00000300 5d 0d c1 30 ab e3 ec b4 54 02 42 01 15 15 1a 6e |]..0....T.B....n| +00000310 6f f1 c6 b1 10 84 2c c8 04 de 2b 52 d5 b4 f7 c9 |o.....,...+R....| +00000320 4f 6d 0e 0e 26 45 1d 7a 28 59 2b 8b f6 92 3a 23 |Om..&E.z(Y+...:#| +00000330 7a 39 9c d5 4e cc 5d c5 45 92 9c d0 5f 33 12 e3 |z9..N.].E..._3..| +00000340 2b 29 39 52 bb 16 aa e1 72 9e b5 fe 99 16 03 03 |+)9R....r.......| +00000350 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -69,21 +69,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 ea 9c f3 e5 4d 7c 48 a5 48 9b |..........M|H.H.| -00000070 87 43 2a 6b 74 e4 8e ca e4 1c c9 87 46 c2 d7 ef |.C*kt.......F...| -00000080 5e 8f c8 60 a9 1c 5f 68 c6 a9 7d 39 a5 8d 13 7c |^..`.._h..}9...|| -00000090 bd 31 6e 19 8d 95 |.1n...| +00000060 00 00 00 00 00 00 20 a3 f8 5a e2 ea f3 09 19 3e |...... ..Z.....>| +00000070 4a 54 69 70 06 5b 17 35 0f ed e7 30 3b 6f eb a1 |JTip.[.5...0;o..| +00000080 cb 9c 35 81 10 2e 34 f7 12 a5 e4 63 20 b2 65 31 |..5...4....c .e1| +00000090 19 da 30 43 39 59 |..0C9Y| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 b1 d2 81 e7 2c |..........@....,| -00000010 ae 4a 72 98 91 5a 36 ae 8b 62 4b 58 55 f0 65 30 |.Jr..Z6..bKXU.e0| -00000020 9a 8d ca 73 13 9f 90 c0 18 fb 10 07 c9 fa 9c aa |...s............| -00000030 67 2a 42 90 11 e5 38 7f 2f 35 ac d7 c7 75 cc 84 |g*B...8./5...u..| -00000040 a4 73 dd 9c f5 0d 3e 5d 25 76 c6 |.s....>]%v.| +00000000 14 03 03 00 01 01 16 03 03 00 40 8d 4d 31 07 df |..........@.M1..| +00000010 ab 41 f5 19 9c 1a 57 fc 33 ab 5f e6 bd 45 b9 fa |.A....W.3._..E..| +00000020 7f db c0 df 72 f2 3b ef aa d4 5e 34 e6 3d 44 7c |....r.;...^4.=D|| +00000030 12 05 c7 57 da 54 b1 e3 66 f0 0a ab cd 15 a5 bf |...W.T..f.......| +00000040 c5 c2 07 a9 d9 a7 2e 5e 29 da da |.......^)..| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 5c f6 d4 35 91 79 5d 47 e6 7d eb |.....\..5.y]G.}.| -00000020 a4 ba d8 94 ee 89 71 60 ba 67 e6 58 79 d7 52 38 |......q`.g.Xy.R8| -00000030 35 07 0a 90 e4 15 03 03 00 30 00 00 00 00 00 00 |5........0......| -00000040 00 00 00 00 00 00 00 00 00 00 73 92 bf 53 22 d7 |..........s..S".| -00000050 80 54 7a 1c 77 d9 a5 16 05 68 c7 c7 5b ce 05 41 |.Tz.w....h..[..A| -00000060 51 d2 a6 2b b9 ba 34 ef 93 5e |Q..+..4..^| +00000010 00 00 00 00 00 dc 03 7b 29 2c 49 64 58 2d dc f7 |.......{),IdX-..| +00000020 26 a1 3b ec 2d e8 30 c4 6c a3 ff e2 bc b5 a4 a6 |&.;.-.0.l.......| +00000030 93 ce 14 bd da 15 03 03 00 30 00 00 00 00 00 00 |.........0......| +00000040 00 00 00 00 00 00 00 00 00 00 a6 77 10 30 15 eb |...........w.0..| +00000050 ed cf 73 5b 74 5d 09 52 4a 5b e2 f0 e4 67 f8 7a |..s[t].RJ[...g.z| +00000060 5e 5e fc ba 7f 80 0a d2 f4 fb |^^........| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM index 155fab6b2ae..fb5af17f0c4 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 52 cc 57 58 95 |....Y...U..R.WX.| -00000010 a0 c0 f9 1d 34 16 31 f5 a5 08 dd 3d 6a 4c c9 96 |....4.1....=jL..| -00000020 aa 8b 7f f3 1e 0c 59 4c 06 c1 2b 20 22 f5 fb 09 |......YL..+ "...| -00000030 f2 7a c3 22 85 2f 16 b6 81 2d 2b d6 12 c2 4d 84 |.z."./...-+...M.| -00000040 7e a9 3f 18 f2 1c f7 44 6c 66 3f 7f c0 2b 00 00 |~.?....Dlf?..+..| +00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 48 |....Y...U..S...H| +00000010 03 36 01 05 56 6f f0 54 d2 c3 d3 41 c2 e2 69 7b |.6..Vo.T...A..i{| +00000020 50 f8 03 ef 3f 5d 7c e6 9c cb fe 20 82 a0 81 fd |P...?]|.... ....| +00000030 72 4b b8 e6 29 76 3b 0f 1d 0a b7 82 9d 0b cf a0 |rK..)v;.........| +00000040 65 b1 56 53 c9 d5 58 7b f0 b6 2d cf c0 2b 00 00 |e.VS..X{..-..+..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,38 +47,38 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 dd |*............A..| -00000280 b5 88 3a be 12 a5 fe 0e 19 f5 76 4f 71 90 93 ca |..:.......vOq...| -00000290 0e b3 62 a2 b0 c0 f2 78 95 90 cb 10 f9 e8 c8 8e |..b....x........| -000002a0 a6 5e 48 ae 8e 96 3d 60 3f 0a b0 73 e8 ea 42 42 |.^H...=`?..s..BB| -000002b0 6e 19 fe e3 ab 30 ff 01 cc ae c1 90 3a 10 85 04 |n....0......:...| -000002c0 03 00 8b 30 81 88 02 42 01 6e b2 79 a1 c1 45 7d |...0...B.n.y..E}| -000002d0 a3 44 45 75 e0 05 b6 68 ee e3 bb 80 2d 88 23 0c |.DEu...h....-.#.| -000002e0 40 ad 68 95 59 0f 49 5b e5 67 2a 5a 9b 29 32 38 |@.h.Y.I[.g*Z.)28| -000002f0 13 a0 f1 6c 11 3f 23 b9 1b 4b 0c 1f 2d 61 5e b3 |...l.?#..K..-a^.| -00000300 de 14 b7 b8 a6 fb 7b 23 1f f3 02 42 01 30 39 22 |......{#...B.09"| -00000310 01 6f d7 a2 83 2a fd 8a 6f f0 c2 d6 1b 0f b4 17 |.o...*..o.......| -00000320 d3 50 f7 de 59 20 6a 5c a1 93 65 ed aa fa 8f 6f |.P..Y j\..e....o| -00000330 75 3a b6 ab 33 b6 68 26 0b 8f d5 b2 ca eb 86 27 |u:..3.h&.......'| -00000340 27 72 68 ed ee 42 37 1a ff 8a 68 c3 32 91 16 03 |'rh..B7...h.2...| -00000350 03 00 04 0e 00 00 00 |.......| +00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 86 |*............A..| +00000280 36 b4 78 76 87 70 ed ae 0d 34 70 3d 16 e5 a4 db |6.xv.p...4p=....| +00000290 ae 28 58 4c 01 5a 56 73 a7 0d 34 59 a7 04 75 69 |.(XL.ZVs..4Y..ui| +000002a0 f2 55 24 40 b0 33 c6 93 ff ae e0 14 f5 4b ce a8 |.U$@.3.......K..| +000002b0 e2 e6 9a 67 1d 66 fb 8f fd 56 59 e7 73 f2 2c 04 |...g.f...VY.s.,.| +000002c0 03 00 8a 30 81 87 02 41 73 ab a8 3c 64 17 69 9f |...0...As..<d.i.| +000002d0 4d b2 9b 55 12 60 33 94 cf f3 83 40 2b 7b 1b af |M..U.`3....@+{..| +000002e0 5c f4 cd 02 66 fb 83 04 35 fd ab 74 98 1a 7d f6 |\...f...5..t..}.| +000002f0 9e 50 98 c3 98 e8 56 9c f2 2a b0 30 9d 05 14 58 |.P....V..*.0...X| +00000300 68 6a 88 04 49 07 78 bf 3a 02 42 01 be b2 05 9e |hj..I.x.:.B.....| +00000310 67 da 1e e9 5a 36 98 52 21 9f 43 75 43 ba bb 9a |g...Z6.R!.CuC...| +00000320 e6 e2 65 f4 e0 44 45 08 5a 1e 54 06 dd 5f 60 2e |..e..DE.Z.T.._`.| +00000330 7d e7 55 08 d3 7b 4e 0a c7 da d4 27 34 d4 bd b0 |}.U..{N....'4...| +00000340 12 2f 41 7a ed 71 32 ef ee 12 74 66 00 16 03 03 |./Az.q2...tf....| +00000350 00 04 0e 00 00 00 |......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 8c c6 |.....(..........| -00000060 b4 4f c9 4b f0 81 05 aa aa 88 79 b0 76 fb 56 8a |.O.K......y.v.V.| -00000070 d3 8f 14 ff e2 9b a3 f6 92 77 aa cf f3 4e |.........w...N| +00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 87 7a |.....(.........z| +00000060 82 d7 46 25 1d a6 bb c2 a8 a8 4e a5 d1 f8 02 db |..F%......N.....| +00000070 33 33 ca 78 b6 d3 bd 77 8a 33 23 a7 95 fb |33.x...w.3#...| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 ca a5 27 78 fb |..........(..'x.| -00000010 e9 66 83 4d 71 62 d4 37 2f 01 5c 8b 67 52 98 5d |.f.Mqb.7/.\.gR.]| -00000020 0d a0 94 53 c1 b5 25 00 e2 42 ab 37 67 2e 12 eb |...S..%..B.7g...| -00000030 35 a3 9a |5..| +00000000 14 03 03 00 01 01 16 03 03 00 28 ce a1 9d 01 c0 |..........(.....| +00000010 31 e5 d5 57 16 e1 a6 b3 8b 25 58 0f fa 2a de 3e |1..W.....%X..*.>| +00000020 0c d9 06 11 a6 b0 d7 b0 33 ad 31 73 5b 26 b4 d2 |........3.1s[&..| +00000030 12 56 c8 |.V.| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 e0 be 1e |................| -00000010 a7 0f 73 a6 25 ca 9e d3 0a ad 6b e7 e9 db 21 a1 |..s.%.....k...!.| -00000020 70 5f c1 15 03 03 00 1a 00 00 00 00 00 00 00 02 |p_..............| -00000030 c3 af f9 8c 63 94 cb e4 99 6d b7 32 80 22 f7 1f |....c....m.2."..| -00000040 02 87 |..| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 d5 04 4c |...............L| +00000010 7b 35 b4 d7 90 ae fe 00 d2 f2 4b 76 f1 36 5e 24 |{5........Kv.6^$| +00000020 4a aa 94 15 03 03 00 1a 00 00 00 00 00 00 00 02 |J...............| +00000030 d3 1c 41 37 ab f6 17 79 f0 01 a4 19 a5 75 7a 8e |..A7...y.....uz.| +00000040 a3 b2 |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES index ae137d87845..5336bbbad8f 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 52 cc 57 58 64 |....Y...U..R.WXd| -00000010 28 c0 0d 0a be 3a aa 96 4e 92 8d 9d f2 19 ab de |(....:..N.......| -00000020 b2 05 3a 61 13 78 60 7e 96 24 b2 20 a3 06 80 14 |..:a.x`~.$. ....| -00000030 15 52 89 1b d4 84 94 8b ed 66 8d 75 63 8f dc 5a |.R.......f.uc..Z| -00000040 a8 20 14 65 5d ce 7e 2f 4b 3e 1e 09 c0 13 00 00 |. .e].~/K>......| +00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 41 |....Y...U..S...A| +00000010 95 cc 56 30 65 46 24 75 d5 9e 3c a7 5b 6c 99 fe |..V0eF$u..<.[l..| +00000020 86 35 23 42 3a 8f 4d 4c b9 98 7d 20 a7 46 43 72 |.5#B:.ML..} .FCr| +00000030 66 bb b6 ad ff ad cf 63 37 fe 6b b4 78 94 08 49 |f......c7.k.x..I| +00000040 54 06 ed f4 85 73 38 4a c6 fe b6 98 c0 13 00 00 |T....s8J........| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| 00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| @@ -58,20 +58,20 @@ 000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| 00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| 00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| -00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 33 |.............A.3| -00000330 96 55 c1 5e 9d c4 a1 23 86 5b e8 df f9 7d d4 d0 |.U.^...#.[...}..| -00000340 5f 61 9a c6 24 be a6 4b ce 08 6e 9f 8f ef 08 66 |_a..$..K..n....f| -00000350 9f a5 2e e7 04 c9 f2 d9 ab ef fa 62 28 a0 01 7a |...........b(..z| -00000360 d9 d6 44 9b c3 25 dc 5e a9 75 ea 8d 2f e8 63 04 |..D..%.^.u../.c.| -00000370 01 00 80 ba b3 36 74 0f 2c 3a c2 a3 2c ae 74 dc |.....6t.,:..,.t.| -00000380 f8 90 ba 91 10 a3 c1 8e 2b bf 2c b4 05 78 12 ff |........+.,..x..| -00000390 ec 62 b3 db f2 27 3d d0 0f bb 7d 1e f6 8f fd ee |.b...'=...}.....| -000003a0 53 37 be 6a 9e d9 21 42 ea 20 1e d8 fc eb 3c 79 |S7.j..!B. ....<y| -000003b0 98 85 ab fe 9b 2d 63 77 cb 13 32 32 81 94 3e 53 |.....-cw..22..>S| -000003c0 4f a7 63 c4 78 2d a2 48 08 ea f6 2a 50 24 33 f4 |O.c.x-.H...*P$3.| -000003d0 9f 10 63 13 80 4e ec 5e 68 e3 18 f0 7b a4 2f 16 |..c..N.^h...{./.| -000003e0 db c0 aa 8c a0 ee 47 65 a9 57 f3 a5 ef 6a 45 f5 |......Ge.W...jE.| -000003f0 e2 54 cd 16 03 03 00 04 0e 00 00 00 |.T..........| +00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 48 |.............A.H| +00000330 68 d8 8a 10 b4 bf eb 8d d1 98 b0 a6 f4 47 5d 91 |h............G].| +00000340 61 da 50 d9 85 7b 5d 90 02 2c 38 c9 af 81 d3 55 |a.P..{]..,8....U| +00000350 07 62 b1 62 58 7f 39 94 d7 91 96 a8 1f 47 60 a5 |.b.bX.9......G`.| +00000360 c0 04 f2 fb cb 15 75 a6 16 3f 94 53 7c ff dd 04 |......u..?.S|...| +00000370 01 00 80 b9 82 fa 0b f8 8c 94 2c 6e 05 81 7d 80 |..........,n..}.| +00000380 5d 9a 77 78 af c8 33 5d 89 7e 2e 3c e5 72 66 a8 |].wx..3].~.<.rf.| +00000390 f1 5c 02 04 02 70 76 7b 45 ff 0d 29 a0 cb 0d db |.\...pv{E..)....| +000003a0 7a 4c c4 13 19 cd 47 b2 f1 c9 43 4f 95 d2 f1 c6 |zL....G...CO....| +000003b0 bc ae 31 4a 9d de 80 b2 a4 b7 b6 dd 8c 03 3e 2a |..1J..........>*| +000003c0 46 5e d1 e7 5b c5 9e 06 58 f3 55 b2 77 09 f3 98 |F^..[...X.U.w...| +000003d0 d5 7f 5a 74 64 7e 48 22 8f 7d a8 68 b6 1d 90 df |..Ztd~H".}.h....| +000003e0 2c 91 d7 c5 07 3d d1 6f e9 c1 91 03 3c 23 5a 56 |,....=.o....<#ZV| +000003f0 3b b2 c2 16 03 03 00 04 0e 00 00 00 |;...........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -79,21 +79,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 73 06 31 ab 8e cc e0 db 1a fe |......s.1.......| -00000070 7e d1 5b 2b 96 93 ee 2d 76 54 17 f9 c2 73 e8 62 |~.[+...-vT...s.b| -00000080 f0 39 31 02 72 e9 ae 08 75 2d f1 f3 82 06 17 57 |.91.r...u-.....W| -00000090 b7 aa c2 79 9f 8e |...y..| +00000060 00 00 00 00 00 00 59 e6 92 05 27 ec 09 2c b0 a5 |......Y...'..,..| +00000070 2a fb 7e f1 03 53 16 63 68 a1 86 13 bb da 98 27 |*.~..S.ch......'| +00000080 6d 42 08 35 6a ec 58 61 2a 4d 44 ec ae c5 b9 d2 |mB.5j.Xa*MD.....| +00000090 76 57 1f 75 9f 8d |vW.u..| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 dc c3 03 17 76 |..........@....v| -00000010 d0 a5 61 9e 47 6a 1a 01 d0 21 92 c5 d5 f9 69 ba |..a.Gj...!....i.| -00000020 5e 82 2e d3 fc 4b a4 af 78 9d 47 6e b8 33 dc 8b |^....K..x.Gn.3..| -00000030 a0 94 b5 72 ea 4a 7d fc ea f5 6e b6 c9 00 73 d1 |...r.J}...n...s.| -00000040 3e cb 44 ef 0c fc fc ff 1e 87 8e |>.D........| +00000000 14 03 03 00 01 01 16 03 03 00 40 6e 03 d0 e6 98 |..........@n....| +00000010 1f f5 39 7b 06 9f 95 f0 7a 88 35 7c 55 db c3 2f |..9{....z.5|U../| +00000020 00 ef 5b d3 62 87 a2 94 da 2f f6 4a 89 c9 a8 3d |..[.b..../.J...=| +00000030 3a 92 db 77 35 92 01 4b f5 c5 6b 95 09 9f cd 79 |:..w5..K..k....y| +00000040 3c af 37 5b 27 bf 93 3e 04 55 71 |<.7['..>.Uq| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 de 2e e3 8e d3 a5 e5 64 8e 22 f7 |............d.".| -00000020 09 00 15 06 cb e9 d3 c5 3c 17 41 2f 5b a8 ce 09 |........<.A/[...| -00000030 70 59 47 24 22 15 03 03 00 30 00 00 00 00 00 00 |pYG$"....0......| -00000040 00 00 00 00 00 00 00 00 00 00 6a af 3f c1 54 6b |..........j.?.Tk| -00000050 14 64 23 c4 94 79 82 fd 78 84 ef 04 6f 64 fd 3e |.d#..y..x...od.>| -00000060 20 ff a0 11 ed fb d1 fb ff 07 | .........| +00000010 00 00 00 00 00 bc c9 d0 8e 80 14 de 32 18 49 e8 |............2.I.| +00000020 20 dc 5e 6c e4 6d 14 00 df 51 71 fb 86 95 16 4c | .^l.m...Qq....L| +00000030 04 8e 71 e1 48 15 03 03 00 30 00 00 00 00 00 00 |..q.H....0......| +00000040 00 00 00 00 00 00 00 00 00 00 b7 6d 30 72 61 53 |...........m0raS| +00000050 d8 0a d4 1d ae e5 d4 22 46 c9 d5 4e 4a 86 f5 ac |......."F..NJ...| +00000060 72 98 c6 db 38 29 97 2c 84 0b |r...8).,..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 index 2c6e776848e..0377f052ae6 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 @@ -8,11 +8,11 @@ 00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| 00000070 03 02 01 02 03 ff 01 00 01 00 |..........| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 52 cc 57 58 70 |....Q...M..R.WXp| -00000010 03 50 58 32 ec de bc ae 18 e7 24 15 2b 4d cc d5 |.PX2......$.+M..| -00000020 1f 40 db 80 5b 19 d9 3f 48 4b 06 20 87 fe d3 d4 |.@..[..?HK. ....| -00000030 51 42 74 9c cf 9d fd 31 c3 53 28 f1 a4 21 16 d6 |QBt....1.S(..!..| -00000040 4f 5a 22 09 9d 99 89 7c f9 e7 5b 49 00 05 00 00 |OZ"....|..[I....| +00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 02 9d |....Q...M..S....| +00000010 2e 4e d9 17 4a 35 fa 9d 94 f6 45 0a f6 6b 5d 1c |.N..J5....E..k].| +00000020 1e 15 19 8d 6d 94 cc 90 d9 39 94 20 8b 4b de 76 |....m....9. .K.v| +00000030 d5 64 5d b7 19 df e7 eb 7e a0 22 c4 09 38 a0 12 |.d].....~."..8..| +00000040 d5 59 10 c8 31 06 dc fc e4 9d d1 80 00 05 00 00 |.Y..1...........| 00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -69,15 +69,15 @@ 00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 03 00 01 |5..C.0oUN.p.....| -00000090 01 16 03 03 00 24 fb 2b 2f c5 19 90 a6 bc 81 c0 |.....$.+/.......| -000000a0 ac 6b e6 1f e2 af be 10 b4 a0 c7 31 aa d8 cc a2 |.k.........1....| -000000b0 ce 51 1e 8e d6 00 76 27 72 53 |.Q....v'rS| +00000090 01 16 03 03 00 24 37 14 b2 97 7b b5 f0 9a 38 05 |.....$7...{...8.| +000000a0 22 35 69 9c 95 2f 86 4b 37 98 22 db 4e 9a 46 9c |"5i../.K7.".N.F.| +000000b0 b9 81 74 72 58 18 53 0c 5c 3c |..trX.S.\<| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 d4 c8 b3 8a 87 |..........$.....| -00000010 b5 0d 01 80 fc 2c df 18 ca 17 fd 06 ad 31 29 13 |.....,.......1).| -00000020 5f f9 b4 75 ad 49 c8 de ec 1a ee 57 6b 1a 81 |_..u.I.....Wk..| +00000000 14 03 03 00 01 01 16 03 03 00 24 3c b3 e7 77 5a |..........$<..wZ| +00000010 7c 36 5a 74 74 26 8d 5b 5a 09 96 60 e8 24 45 2f ||6Ztt&.[Z..`.$E/| +00000020 c2 39 14 5e db 58 12 49 ad a8 b6 ea ef 58 16 |.9.^.X.I.....X.| >>> Flow 5 (client to server) -00000000 17 03 03 00 1a 8b ce be 7d c7 06 42 d0 9b 65 6c |........}..B..el| -00000010 23 0e 84 ef e0 a3 ec 42 4e 70 14 65 78 ad 52 15 |#......BNp.ex.R.| -00000020 03 03 00 16 49 5f f2 e2 e0 8f d3 54 68 2a d6 ab |....I_.....Th*..| -00000030 28 be 50 3d 62 8b 1a b3 5b e5 |(.P=b...[.| +00000000 17 03 03 00 1a 6d 29 d7 ba 2f 85 02 b6 f0 82 64 |.....m)../.....d| +00000010 6c 55 ae ab f6 fd 14 ff b8 38 f0 f8 a6 ea cc 15 |lU.......8......| +00000020 03 03 00 16 10 c5 d9 41 7b e2 89 67 dc 29 8e f8 |.......A{..g.)..| +00000030 b5 ab 32 91 44 2c 27 84 49 f7 |..2.D,'.I.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES index d90f02bd355..9b8cb4d9b62 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 76 01 00 00 72 03 01 52 cc 57 59 19 |....v...r..R.WY.| -00000010 3d b7 7c 4b 54 8d ca 3a b1 4c 4e a9 78 86 d9 74 |=.|KT..:.LN.x..t| -00000020 87 2f f3 86 bf ac cc f4 11 75 b7 00 00 04 c0 0a |./.......u......| +00000000 16 03 01 00 76 01 00 00 72 03 01 53 04 f0 f9 4b |....v...r..S...K| +00000010 30 a8 68 d0 79 13 14 69 ee 3b 5d 05 cb 71 63 43 |0.h.y..i.;]..qcC| +00000020 4a 55 6b 05 25 53 19 ba e0 2f b1 00 00 04 c0 0a |JUk.%S.../......| 00000030 00 ff 01 00 00 45 00 0b 00 04 03 00 01 02 00 0a |.....E..........| 00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............| 00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................| @@ -44,50 +44,41 @@ 00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7| 00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.| 00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1| -00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 01 1a 0c 00 |{j.9....*.......| -00000250 01 16 03 00 19 85 04 01 39 dc ee 44 17 5e db d7 |........9..D.^..| -00000260 27 af b6 56 d9 b4 43 5a 99 cf aa 31 37 0c 6f 3a |'..V..CZ...17.o:| -00000270 a0 f8 53 c4 74 d1 91 0a 46 f5 38 3b 5c 09 d8 97 |..S.t...F.8;\...| -00000280 dc 4b aa 70 26 48 f2 d6 0b 31 c9 f8 d4 98 43 e1 |.K.p&H...1....C.| -00000290 6c d5 c7 b2 8e 0b 01 e6 b6 00 28 80 7b fc 96 8f |l.........(.{...| -000002a0 0d a2 4f b0 79 af dc 61 28 63 33 78 f6 31 39 fd |..O.y..a(c3x.19.| -000002b0 8a f4 15 18 11 fe db d5 07 da 2c ed 49 a0 23 bf |..........,.I.#.| -000002c0 d0 3a 38 1d 54 ae 1c 7b ea 29 ee d0 38 c1 76 a7 |.:8.T..{.)..8.v.| -000002d0 7f 2a f4 ce 1e ac cc 94 79 90 33 00 8b 30 81 88 |.*......y.3..0..| -000002e0 02 42 00 c6 85 8e 06 b7 04 04 e9 cd 9e 3e cb 66 |.B...........>.f| -000002f0 23 95 b4 42 9c 64 81 39 05 3f b5 21 f8 28 af 60 |#..B.d.9.?.!.(.`| -00000300 6b 4d 3d ba a1 4b 5e 77 ef e7 59 28 fe 1d c1 27 |kM=..K^w..Y(...'| -00000310 a2 ff a8 de 33 48 b3 c1 85 6a 42 9b f9 7e 7e 31 |....3H...jB..~~1| -00000320 c2 e5 bd 66 02 42 00 ad 7d 06 35 ab ec 8d ac d4 |...f.B..}.5.....| -00000330 ba 1b 49 5e 05 5f f0 97 93 82 b8 2b 8d 91 98 63 |..I^._.....+...c| -00000340 8e b4 14 62 db 1e c9 2b 30 f8 41 9b a6 e6 bc de |...b...+0.A.....| -00000350 0e 68 30 21 e4 33 62 b4 3c 00 12 33 3c d2 bb 9e |.h0!.3b.<..3<...| -00000360 a9 db ef 22 41 ed 2b 1a 16 03 01 00 04 0e 00 00 |..."A.+.........| -00000370 00 |.| +00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 00 d6 0c 00 |{j.9....*.......| +00000250 00 d2 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| +00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| +00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| +00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| +00000290 41 03 56 6b dc 5a 89 00 8b 30 81 88 02 42 00 c6 |A.Vk.Z...0...B..| +000002a0 85 8e 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 |.........>.f#..B| +000002b0 9c 64 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba |.d.9.?.!.(.`kM=.| +000002c0 a1 4b 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de |.K^w..Y(...'....| +000002d0 33 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 |3H...jB..~~1...f| +000002e0 02 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b 49 5e |.B..}.5.......I^| +000002f0 05 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 14 62 |._.....+...c...b| +00000300 db 1e c9 2b 30 f8 41 9b a6 e6 bc de 0e 68 30 21 |...+0.A......h0!| +00000310 d8 ef 2f 05 42 da f2 e0 2c 06 33 1d 0d 9a 1a 75 |../.B...,.3....u| +00000320 59 a7 3a bc 16 03 01 00 04 0e 00 00 00 |Y.:..........| >>> Flow 3 (client to server) -00000000 16 03 01 00 8a 10 00 00 86 85 04 00 be 44 15 9d |.............D..| -00000010 89 bc 13 e7 55 cf 7a f9 b1 dc 2b 22 f2 7b a6 33 |....U.z...+".{.3| -00000020 b6 46 de 7d c2 08 a6 67 15 7d 3e c2 02 d4 30 dc |.F.}...g.}>...0.| -00000030 35 37 7e ee fb 12 8c 74 c0 bf ea db 72 06 cd 52 |57~....t....r..R| -00000040 1a e9 36 2e c5 5d 22 9e 56 e5 8d 9f a5 01 e2 e6 |..6..]".V.......| -00000050 f5 77 64 05 80 c0 e3 54 9a 89 76 f9 73 64 7d 0e |.wd....T..v.sd}.| -00000060 bf d7 b3 57 a2 6c 4a 34 80 53 96 90 61 56 34 ad |...W.lJ4.S..aV4.| -00000070 75 44 54 79 dd 71 16 fe 4f 27 4f d0 0c d0 1e b6 |uDTy.q..O'O.....| -00000080 82 c4 b2 e9 a1 87 fd a7 2a 6a 5d 79 b8 f1 4e 14 |........*j]y..N.| -00000090 03 01 00 01 01 16 03 01 00 30 db c5 5f 9b 03 77 |.........0.._..w| -000000a0 c9 aa 5e 74 fd 0c f7 28 fe 40 8b 0e 2d 85 1e 25 |..^t...(.@..-..%| -000000b0 96 23 79 48 2c 3f 5d 9b 57 f0 34 8d 87 81 13 d9 |.#yH,?].W.4.....| -000000c0 ed 72 f6 51 bf d7 6e 8b 61 3d |.r.Q..n.a=| +00000000 16 03 01 00 46 10 00 00 42 41 04 08 28 cf bd 3c |....F...BA..(..<| +00000010 3c cc 98 9e 73 3f 92 a7 cb 22 83 3b c7 61 46 0e |<...s?...".;.aF.| +00000020 4d 7c 30 b5 06 85 2f 01 be b5 40 e2 64 1e 45 c1 |M|0.../...@.d.E.| +00000030 9d 73 95 d5 65 92 0b 9b e7 6f c6 91 ab b6 fa be |.s..e....o......| +00000040 61 83 a7 f2 eb f5 65 31 fe 24 7b 14 03 01 00 01 |a.....e1.${.....| +00000050 01 16 03 01 00 30 15 d1 c4 ca 0b 01 84 13 5a ba |.....0........Z.| +00000060 89 04 87 73 7c bb d8 89 7e 10 27 ba 6f 5d dc d3 |...s|...~.'.o]..| +00000070 b5 ef 32 86 58 cc fb eb 5c 32 9e 95 ef 01 1c ac |..2.X...\2......| +00000080 dc 8e df 7f fe 0a |......| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 95 b6 20 60 88 |..........0.. `.| -00000010 5f 23 11 06 83 f5 20 2d 42 77 36 c2 84 1b 70 90 |_#.... -Bw6...p.| -00000020 12 af d3 5e fa b0 59 6b 1e 91 0a c3 e0 37 40 94 |...^..Yk.....7@.| -00000030 07 c0 2b 84 74 41 fa fd 7c 41 59 17 03 01 00 20 |..+.tA..|AY.... | -00000040 de a7 ea 4e f8 88 22 6d cb 3d d5 ed 60 7c b9 a0 |...N.."m.=..`|..| -00000050 ba c5 19 14 86 3a 98 ea d3 73 68 1e d4 f8 0e 12 |.....:...sh.....| -00000060 17 03 01 00 30 30 50 48 84 2e b0 15 0a 5f 64 3c |....00PH....._d<| -00000070 fc 19 aa 89 7d 6e ba 84 56 56 66 15 6e d4 b9 35 |....}n..VVf.n..5| -00000080 20 ac 98 0d 8d 09 e1 80 8d 32 c8 99 d2 70 41 3a | ........2...pA:| -00000090 9b 62 d6 48 b1 15 03 01 00 20 9a 16 01 aa d0 6f |.b.H..... .....o| -000000a0 d4 d3 bb 5d 57 c0 7c d1 a8 d4 67 5d 5e 1d be 7d |...]W.|...g]^..}| -000000b0 d2 78 4a 33 93 ae 53 cc fb a0 |.xJ3..S...| +00000000 14 03 01 00 01 01 16 03 01 00 30 e8 48 86 81 3c |..........0.H..<| +00000010 f5 25 5c 94 a9 06 c4 5c 71 62 b1 43 76 ec 2c 44 |.%\....\qb.Cv.,D| +00000020 95 b5 8c 95 d2 ff 82 92 b6 fc 52 75 03 c6 a1 f0 |..........Ru....| +00000030 99 6d b1 ed ec 68 6c d7 9f 18 50 17 03 01 00 20 |.m...hl...P.... | +00000040 32 d9 26 8a 81 b8 9d a5 7b fd d5 4e 7a db 2e 29 |2.&.....{..Nz..)| +00000050 58 9a 4f 6a 27 18 bc dc c2 49 b8 65 cb 8e 16 5a |X.Oj'....I.e...Z| +00000060 17 03 01 00 30 c4 56 0a ad 9a 82 cb 3e 32 f1 7c |....0.V.....>2.|| +00000070 95 6e dd cd e9 4d f0 e5 2d c9 a3 f7 de bb d7 fd |.n...M..-.......| +00000080 84 bb df 34 8c 64 1f 03 58 64 19 4a 5b 7a a8 81 |...4.d..Xd.J[z..| +00000090 52 bb 51 0a 43 15 03 01 00 20 89 18 7a 40 ec 49 |R.Q.C.... ..z@.I| +000000a0 52 d5 d3 20 ac 07 eb e9 4a 78 23 cf e7 21 32 74 |R.. ....Jx#..!2t| +000000b0 ec 40 8d a8 f4 33 1c ae 93 cf |.@...3....| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA index c170408e480..0ab8b8d74c5 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 ca 01 00 00 c6 03 03 52 cc 5e 7f 49 |...........R.^.I| -00000010 8a 7a 88 c0 85 24 6b 3d 95 ff 0f 9e 91 32 c2 a4 |.z...$k=.....2..| -00000020 6b 4c 53 e4 b4 4c 40 72 e4 54 27 00 00 32 c0 30 |kLS..L@r.T'..2.0| +00000000 16 03 01 00 ca 01 00 00 c6 03 03 53 04 f1 3f 5f |...........S..?_| +00000010 f4 ef 1f b3 41 0b 54 e4 4d 56 0a 31 22 b8 5c 73 |....A.T.MV.1".\s| +00000020 a3 cb b5 b2 9d 43 f1 83 bc d3 bd 00 00 32 c0 30 |.....C.......2.0| 00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..| 00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2| 00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5| @@ -49,51 +49,43 @@ 00000210 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e |3.......7z..z...| 00000220 dd d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 |...i..|V..1x+..x| 00000230 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 |.....N6$1{j.9...| -00000240 8f 2a 16 03 03 01 1c 0c 00 01 18 03 00 19 85 04 |.*..............| -00000250 01 39 dc ee 44 17 5e db d7 27 af b6 56 d9 b4 43 |.9..D.^..'..V..C| -00000260 5a 99 cf aa 31 37 0c 6f 3a a0 f8 53 c4 74 d1 91 |Z...17.o:..S.t..| -00000270 0a 46 f5 38 3b 5c 09 d8 97 dc 4b aa 70 26 48 f2 |.F.8;\....K.p&H.| -00000280 d6 0b 31 c9 f8 d4 98 43 e1 6c d5 c7 b2 8e 0b 01 |..1....C.l......| -00000290 e6 b6 00 28 80 7b fc 96 8f 0d a2 4f b0 79 af dc |...(.{.....O.y..| -000002a0 61 28 63 33 78 f6 31 39 fd 8a f4 15 18 11 fe db |a(c3x.19........| -000002b0 d5 07 da 2c ed 49 a0 23 bf d0 3a 38 1d 54 ae 1c |...,.I.#..:8.T..| -000002c0 7b ea 29 ee d0 38 c1 76 a7 7f 2a f4 ce 1e ac cc |{.)..8.v..*.....| -000002d0 94 79 90 33 04 03 00 8b 30 81 88 02 42 00 c6 85 |.y.3....0...B...| -000002e0 8e 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c |........>.f#..B.| -000002f0 64 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 |d.9.?.!.(.`kM=..| -00000300 4b 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 |K^w..Y(...'....3| -00000310 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 |H...jB..~~1...f.| -00000320 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b 49 5e 05 |B..}.5.......I^.| -00000330 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 14 62 db |_.....+...c...b.| -00000340 1e c9 2b ca fe c9 88 b7 3d 46 d2 5b 55 de bc 9a |..+.....=F.[U...| -00000350 66 c9 cf b7 3d e8 c8 62 24 93 d8 db 12 77 2a 6c |f...=..b$....w*l| -00000360 08 66 48 16 03 03 00 04 0e 00 00 00 |.fH.........| +00000240 8f 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 |.*............A.| +00000250 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.| +00000260 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^| +00000270 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B| +00000280 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.| +00000290 04 03 00 8b 30 81 88 02 42 00 c6 85 8e 06 b7 04 |....0...B.......| +000002a0 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 81 39 05 |....>.f#..B.d.9.| +000002b0 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b 5e 77 ef |?.!.(.`kM=..K^w.| +000002c0 e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 b3 c1 85 |.Y(...'....3H...| +000002d0 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 42 00 ad 7d |jB..~~1...f.B..}| +000002e0 06 35 ab ec 8d ac d4 ba 1b 49 5e 05 5f f0 97 93 |.5.......I^._...| +000002f0 82 b8 2b 8d 91 98 63 8e b4 14 62 db 1e c9 2b 64 |..+...c...b...+d| +00000300 e9 e6 bf 15 5b 67 c2 40 90 c6 1f b7 92 db 4b f6 |....[g.@......K.| +00000310 f4 db ae 82 f1 4f 02 75 52 40 38 10 ff 35 f0 16 |.....O.uR@8..5..| +00000320 03 03 00 04 0e 00 00 00 |........| >>> Flow 3 (client to server) -00000000 16 03 03 00 8a 10 00 00 86 85 04 01 fd 02 a1 b1 |................| -00000010 56 3c 37 37 da 78 37 d9 07 ee 09 35 4f ff 3e db |V<77.x7....5O.>.| -00000020 da da 23 12 2c 40 12 dd 73 e7 2c c5 2e fb 37 24 |..#.,@..s.,...7$| -00000030 2f 97 95 b4 6c 1e 56 6c 4e 49 d5 89 21 8b ca 74 |/...l.VlNI..!..t| -00000040 85 1b 24 96 fb 28 cc 64 70 59 fc be 18 00 00 98 |..$..(.dpY......| -00000050 9a f6 c9 26 26 6d ce 48 7b 3b 62 ea dd da 73 8b |...&&m.H{;b...s.| -00000060 71 48 18 71 52 2d 22 1d 7c 67 55 1b 6b fa 44 40 |qH.qR-".|gU.k.D@| -00000070 be 87 0f 52 21 4b 86 b4 f0 6d 1b dd e7 0f f8 ef |...R!K...m......| -00000080 1a 09 8b 66 b9 60 38 da 6f 9d 9d 74 58 d9 35 14 |...f.`8.o..tX.5.| -00000090 03 03 00 01 01 16 03 03 00 40 5b 98 11 9d d4 83 |.........@[.....| -000000a0 13 b6 28 4b 85 61 0b e1 bf 36 3f 43 c0 95 3d 7e |..(K.a...6?C..=~| -000000b0 95 ea 84 14 e6 6d 1a e0 20 50 b4 02 d0 b2 e9 5f |.....m.. P....._| -000000c0 07 82 a8 6a 1e 7c 1e f7 6c b5 be 1b 20 2e 98 4e |...j.|..l... ..N| -000000d0 ab 8d 1e f2 56 88 ed ef aa 39 |....V....9| +00000000 16 03 03 00 46 10 00 00 42 41 04 d8 94 c4 05 26 |....F...BA.....&| +00000010 76 29 2d 0e ec 47 b6 50 d5 a3 da 2a ba 02 11 37 |v)-..G.P...*...7| +00000020 3d ef e6 2a db d0 47 47 a7 9a 5f 43 2d 98 78 26 |=..*..GG.._C-.x&| +00000030 81 e2 f1 ba fe f7 66 c6 61 cb c1 b7 60 62 34 a5 |......f.a...`b4.| +00000040 78 67 50 3d 9a 0e 4a 8c 8f d7 10 14 03 03 00 01 |xgP=..J.........| +00000050 01 16 03 03 00 40 5e 46 b0 5d 30 f6 da 8f 9e 67 |.....@^F.]0....g| +00000060 f5 3e bd fe c9 b8 53 b2 10 d5 7c 0e 34 e3 93 6d |.>....S...|.4..m| +00000070 0e 8e 8a 2b df fb 9a 0f a5 23 55 e7 0a 4b e2 d3 |...+.....#U..K..| +00000080 db 15 e8 52 74 26 78 b3 b0 56 65 63 ac ae 1e c0 |...Rt&x..Vec....| +00000090 0b f4 92 56 a9 04 |...V..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 7e f1 fc 1d 0c |...........~....| -00000020 f5 a2 c6 35 de 78 97 62 72 3f 05 6c a3 a8 0e cb |...5.x.br?.l....| -00000030 10 7e c0 3d 28 c7 d9 4e 71 f4 18 d7 14 42 09 5c |.~.=(..Nq....B.\| -00000040 22 26 04 1f 04 12 9f 88 3d 4a 4a 17 03 03 00 40 |"&......=JJ....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 16 a9 63 0a 99 |.............c..| +00000020 21 8a fc 5c b3 ee 05 71 4e 75 c0 d9 40 54 0d 3e |!..\...qNu..@T.>| +00000030 4e 5d 44 b7 4b 5d a9 e7 5a 30 ed b6 d5 08 50 b1 |N]D.K]..Z0....P.| +00000040 e8 8c 54 eb 1b 39 7a f9 3b ac 2e 17 03 03 00 40 |..T..9z.;......@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 0f 35 50 38 be 3a c7 4e c4 de 36 63 85 c1 7a 78 |.5P8.:.N..6c..zx| -00000070 c6 7f 65 8c d1 44 c5 7e 45 32 60 88 93 bf 10 82 |..e..D.~E2`.....| -00000080 4b 1a 46 9a 60 54 c5 ee 2a c1 86 02 a7 b6 d5 ea |K.F.`T..*.......| +00000060 96 03 20 2b 20 c4 c1 9a 76 7b f3 96 bd 33 ed e6 |.. + ...v{...3..| +00000070 38 48 ea 53 d5 e0 62 b5 7e 1a 36 a8 dd 9f 2d 4b |8H.S..b.~.6...-K| +00000080 06 0d ae f6 bc 99 14 b3 93 14 27 63 e2 a0 c8 76 |..........'c...v| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 78 6c 41 05 2f 6f c2 d7 70 54 24 |.....xlA./o..pT$| -000000b0 66 01 2c 1e 71 43 05 3a 1b 9e 86 ff b4 c5 65 b2 |f.,.qC.:......e.| -000000c0 f0 f8 ef 6b 25 |...k%| +000000a0 00 00 00 00 00 48 af e1 e4 11 e1 b7 03 19 b0 e3 |.....H..........| +000000b0 e6 a9 66 d8 ac af aa 03 f6 0d 51 df 9a 27 78 3a |..f.......Q..'x:| +000000c0 56 5a 03 1a 4c |VZ..L| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA index de2f0aba8b3..88abb15a7e6 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 ca 01 00 00 c6 03 03 52 cc 5e 7f ec |...........R.^..| -00000010 d7 b4 0c ac 92 e8 d1 6e df c1 e6 ee f5 84 5e 1a |.......n......^.| -00000020 1d 05 bf 2d 3f 71 91 d1 cc b7 f8 00 00 32 c0 30 |...-?q.......2.0| +00000000 16 03 01 00 ca 01 00 00 c6 03 03 53 04 f1 3f cc |...........S..?.| +00000010 41 74 00 07 cb ae 3b 30 79 48 51 60 41 a3 8c ab |At....;0yHQ`A...| +00000020 dc 76 f9 74 52 1e c5 fb a9 69 c2 00 00 32 c0 30 |.v.tR....i...2.0| 00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..| 00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2| 00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5| @@ -60,51 +60,42 @@ 000002c0 5a 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd |Z_3....u....R...| 000002d0 98 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 |... _..........W| 000002e0 e9 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 |.p.&mq..&n8P)l..| -000002f0 bd d9 16 03 03 01 11 0c 00 01 0d 03 00 19 85 04 |................| -00000300 01 39 dc ee 44 17 5e db d7 27 af b6 56 d9 b4 43 |.9..D.^..'..V..C| -00000310 5a 99 cf aa 31 37 0c 6f 3a a0 f8 53 c4 74 d1 91 |Z...17.o:..S.t..| -00000320 0a 46 f5 38 3b 5c 09 d8 97 dc 4b aa 70 26 48 f2 |.F.8;\....K.p&H.| -00000330 d6 0b 31 c9 f8 d4 98 43 e1 6c d5 c7 b2 8e 0b 01 |..1....C.l......| -00000340 e6 b6 00 28 80 7b fc 96 8f 0d a2 4f b0 79 af dc |...(.{.....O.y..| -00000350 61 28 63 33 78 f6 31 39 fd 8a f4 15 18 11 fe db |a(c3x.19........| -00000360 d5 07 da 2c ed 49 a0 23 bf d0 3a 38 1d 54 ae 1c |...,.I.#..:8.T..| -00000370 7b ea 29 ee d0 38 c1 76 a7 7f 2a f4 ce 1e ac cc |{.)..8.v..*.....| -00000380 94 79 90 33 04 01 00 80 ad 89 a5 bf 16 74 a1 14 |.y.3.........t..| -00000390 c4 a1 09 31 95 69 e4 b4 e3 8d df 99 73 cd e6 94 |...1.i......s...| -000003a0 eb ca 07 7f f4 36 ca 31 1c 29 f0 f0 d8 40 6b 19 |.....6.1.)...@k.| -000003b0 f2 15 be f1 76 22 b3 82 f7 bf 2b 09 0f cd 31 c8 |....v"....+...1.| -000003c0 69 7b 7b 1a ed a1 f7 85 6e 04 5c fa a5 20 c0 ef |i{{.....n.\.. ..| -000003d0 c6 45 6d 05 25 37 ec f6 94 91 32 f3 c8 d1 f0 13 |.Em.%7....2.....| -000003e0 81 1e 26 bb 4c 47 91 79 ad cf 7e 61 85 54 eb 13 |..&.LG.y..~a.T..| -000003f0 6b b1 15 36 72 bf d1 ad 07 3e 6d bd 44 1a 30 ac |k..6r....>m.D.0.| -00000400 41 39 ad 75 14 bb 11 dc 16 03 03 00 04 0e 00 00 |A9.u............| -00000410 00 |.| +000002f0 bd d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 |..............A.| +00000300 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.| +00000310 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^| +00000320 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B| +00000330 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.| +00000340 04 01 00 80 9d 84 09 35 73 fb f6 ea 94 7b 49 fb |.......5s....{I.| +00000350 c2 70 b1 11 64 5b 93 9f d9 8c f5 56 98 f6 d3 66 |.p..d[.....V...f| +00000360 a6 1d 18 56 88 87 71 3f b0 38 9d 44 1f ad 2c 0d |...V..q?.8.D..,.| +00000370 3a a7 e8 d4 3e 33 3c 41 20 f3 3f 5c e5 fb e3 23 |:...>3<A .?\...#| +00000380 12 48 ff d2 c4 30 7c 8a 51 3f 9f 19 6e 34 d7 60 |.H...0|.Q?..n4.`| +00000390 7d 12 8a aa 90 0f 50 d9 0b 9a b2 d7 66 b1 c6 84 |}.....P.....f...| +000003a0 af 5c e2 5e 16 3e 36 61 73 84 64 89 b3 c1 6d 50 |.\.^.>6as.d...mP| +000003b0 33 55 c7 e1 c5 a5 4c 32 5c 95 dc 07 43 60 49 11 |3U....L2\...C`I.| +000003c0 e9 98 cc ba 16 03 03 00 04 0e 00 00 00 |.............| >>> Flow 3 (client to server) -00000000 16 03 03 00 8a 10 00 00 86 85 04 01 fb 77 96 9a |.............w..| -00000010 82 26 4f 44 b5 2f 32 28 0a dd 51 f5 a4 84 46 a1 |.&OD./2(..Q...F.| -00000020 ba 58 e6 9a 96 1b 85 9f ae 3a 8b db a8 93 81 00 |.X.......:......| -00000030 17 be 24 26 17 fd b8 7c fe 93 7f af 5f 4d c6 47 |..$&...|...._M.G| -00000040 8b 72 5b 23 89 03 d5 a6 fb 6f de 59 15 00 bb 36 |.r[#.....o.Y...6| -00000050 6d 72 03 47 61 b7 7e d4 46 43 b3 e9 9d 2f 61 6a |mr.Ga.~.FC.../aj| -00000060 08 1b 04 70 ac 95 ad bf 18 e5 09 b6 b3 0d 6a bb |...p..........j.| -00000070 e8 77 09 fa 81 2e 8a e1 61 7e 9f 38 d0 67 f5 11 |.w......a~.8.g..| -00000080 f1 62 7f a4 69 4a 42 7a f8 9e 05 26 66 34 6e 14 |.b..iJBz...&f4n.| -00000090 03 03 00 01 01 16 03 03 00 40 2c a1 a8 3a 34 18 |.........@,..:4.| -000000a0 ea a1 d4 28 0b 1a ac ab 51 b1 c5 48 f2 56 8d c7 |...(....Q..H.V..| -000000b0 83 7b 70 44 40 7d 15 1c 00 19 ed 53 21 fe 9d c1 |.{pD@}.....S!...| -000000c0 a2 13 8f a0 0c 51 f5 13 67 1f bf 07 da bc 2d ca |.....Q..g.....-.| -000000d0 7c 0f 53 4b 4a 02 bb 0f 72 c6 ||.SKJ...r.| +00000000 16 03 03 00 46 10 00 00 42 41 04 28 02 84 d5 b4 |....F...BA.(....| +00000010 58 07 47 d5 a0 d6 0b 1d 37 91 e6 34 a4 ad 0b ad |X.G.....7..4....| +00000020 22 01 82 77 a7 32 86 78 83 3a da 75 2f e5 68 7a |"..w.2.x.:.u/.hz| +00000030 de e4 05 e0 02 47 40 4e 38 d2 2c c3 7b da 53 73 |.....G@N8.,.{.Ss| +00000040 19 cb 8b 73 34 72 4d 33 71 39 c8 14 03 03 00 01 |...s4rM3q9......| +00000050 01 16 03 03 00 40 10 63 43 76 83 bd 36 e4 1e 4d |.....@.cCv..6..M| +00000060 7e 13 b0 ac aa c8 ec 90 31 df 84 46 49 68 39 5a |~.......1..FIh9Z| +00000070 05 8b 73 32 86 15 3a 18 57 d8 e2 2c 2d 05 89 93 |..s2..:.W..,-...| +00000080 37 b8 dd 73 33 92 ff a7 b2 53 27 94 b7 25 56 64 |7..s3....S'..%Vd| +00000090 a1 d3 2c f7 6b 71 |..,.kq| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 82 f6 03 51 7f |..............Q.| -00000020 37 19 ec 26 20 db e2 5b 8e 5e 22 29 1a 88 ca f1 |7..& ..[.^")....| -00000030 ad 55 1c 3c 07 1d 05 b6 c4 88 58 84 a0 5d 33 41 |.U.<......X..]3A| -00000040 7a 65 bc ba a1 71 a4 71 df 6c 9d 17 03 03 00 40 |ze...q.q.l.....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 21 5c 31 b1 4b |...........!\1.K| +00000020 96 96 30 8f 79 35 3a 3a 2d 26 67 d0 70 48 be 30 |..0.y5::-&g.pH.0| +00000030 f8 3e e8 c1 cb 1d d5 89 f6 9c 72 bb 1c f9 4d 90 |.>........r...M.| +00000040 9c d7 c6 fa 40 76 a5 61 46 61 24 17 03 03 00 40 |....@v.aFa$....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 8d ca 51 a1 4a b1 23 dc e3 ef 63 5f b0 e8 7a c6 |..Q.J.#...c_..z.| -00000070 97 d7 18 6a 4b 80 3e 5c 7b 79 86 93 60 2c 8b f1 |...jK.>\{y..`,..| -00000080 4e 46 c5 5e 64 0c 98 81 10 6d c5 08 22 f1 02 1d |NF.^d....m.."...| +00000060 94 8a 14 04 06 b9 30 a0 67 fd b2 4c 84 f4 10 93 |......0.g..L....| +00000070 7d d4 2b 23 f0 e9 62 93 c2 20 a2 f2 7c 07 21 4b |}.+#..b.. ..|.!K| +00000080 94 ba 7b 7d cb 77 da 85 93 bd 53 ee ca db 9b 3e |..{}.w....S....>| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 51 19 c4 67 b7 14 6b 5c 49 ac 1d |.....Q..g..k\I..| -000000b0 b3 97 88 42 29 cb f5 06 54 f4 c6 38 9a 47 41 78 |...B)...T..8.GAx| -000000c0 0f 33 21 ac c5 |.3!..| +000000a0 00 00 00 00 00 17 3f 53 8d b3 35 b4 84 ed bb 12 |......?S..5.....| +000000b0 cf 73 25 25 7c c3 d3 bb 1f 5a 6b 73 9a 8a b1 a2 |.s%%|....Zks....| +000000c0 ba 99 f8 0e 43 |....C| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES index fa6cb080c90..aacbb86705a 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 9c 01 00 00 98 03 03 52 cc 57 59 54 |...........R.WYT| -00000010 0b ba f3 ec 2c 33 3e 3e ac b8 c1 d5 d5 ff e3 d3 |....,3>>........| -00000020 63 d0 29 16 aa 5d 96 37 89 90 c4 00 00 04 c0 0a |c.)..].7........| +00000000 16 03 01 00 9c 01 00 00 98 03 03 53 04 f0 f9 09 |...........S....| +00000010 13 56 01 37 84 b1 32 59 4c 73 b1 8e bb 02 1a 32 |.V.7..2YLs.....2| +00000020 db ab 8c e6 ed ad 7f 52 9a 59 39 00 00 04 c0 0a |.......R.Y9.....| 00000030 00 ff 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a |.....k..........| 00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............| 00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................| @@ -47,52 +47,43 @@ 00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7| 00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.| 00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1| -00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 01 1c 0c 00 |{j.9....*.......| -00000250 01 18 03 00 19 85 04 01 39 dc ee 44 17 5e db d7 |........9..D.^..| -00000260 27 af b6 56 d9 b4 43 5a 99 cf aa 31 37 0c 6f 3a |'..V..CZ...17.o:| -00000270 a0 f8 53 c4 74 d1 91 0a 46 f5 38 3b 5c 09 d8 97 |..S.t...F.8;\...| -00000280 dc 4b aa 70 26 48 f2 d6 0b 31 c9 f8 d4 98 43 e1 |.K.p&H...1....C.| -00000290 6c d5 c7 b2 8e 0b 01 e6 b6 00 28 80 7b fc 96 8f |l.........(.{...| -000002a0 0d a2 4f b0 79 af dc 61 28 63 33 78 f6 31 39 fd |..O.y..a(c3x.19.| -000002b0 8a f4 15 18 11 fe db d5 07 da 2c ed 49 a0 23 bf |..........,.I.#.| -000002c0 d0 3a 38 1d 54 ae 1c 7b ea 29 ee d0 38 c1 76 a7 |.:8.T..{.)..8.v.| -000002d0 7f 2a f4 ce 1e ac cc 94 79 90 33 04 03 00 8b 30 |.*......y.3....0| -000002e0 81 88 02 42 00 c6 85 8e 06 b7 04 04 e9 cd 9e 3e |...B...........>| -000002f0 cb 66 23 95 b4 42 9c 64 81 39 05 3f b5 21 f8 28 |.f#..B.d.9.?.!.(| -00000300 af 60 6b 4d 3d ba a1 4b 5e 77 ef e7 59 28 fe 1d |.`kM=..K^w..Y(..| -00000310 c1 27 a2 ff a8 de 33 48 b3 c1 85 6a 42 9b f9 7e |.'....3H...jB..~| -00000320 7e 31 c2 e5 bd 66 02 42 00 ad 7d 06 35 ab ec 8d |~1...f.B..}.5...| -00000330 ac d4 ba 1b 49 5e 05 5f f0 97 93 82 b8 2b 8d 91 |....I^._.....+..| -00000340 98 63 8e b4 14 62 db 1e c9 2b eb 95 36 9b 44 c6 |.c...b...+..6.D.| -00000350 a6 89 58 50 f9 30 94 89 ef 0f 71 ed c0 42 59 11 |..XP.0....q..BY.| -00000360 68 e7 ac 52 2c 1e ed 70 b1 f8 16 03 03 00 04 0e |h..R,..p........| -00000370 00 00 00 |...| +00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......| +00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| +00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| +00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| +00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| +00000290 41 03 56 6b dc 5a 89 04 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B| +000002a0 00 c6 85 8e 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 |...........>.f#.| +000002b0 b4 42 9c 64 81 39 05 3f b5 21 f8 28 af 60 6b 4d |.B.d.9.?.!.(.`kM| +000002c0 3d ba a1 4b 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff |=..K^w..Y(...'..| +000002d0 a8 de 33 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 |..3H...jB..~~1..| +000002e0 bd 66 02 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b |.f.B..}.5.......| +000002f0 49 5e 05 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 |I^._.....+...c..| +00000300 14 62 db 1e c9 2c 13 ae b7 d3 17 38 23 2f f6 7f |.b...,.....8#/..| +00000310 0c 4d d3 33 d2 79 d1 77 ee cb b1 c2 fc 34 b8 69 |.M.3.y.w.....4.i| +00000320 f9 10 8b 61 89 85 16 03 03 00 04 0e 00 00 00 |...a...........| >>> Flow 3 (client to server) -00000000 16 03 03 00 8a 10 00 00 86 85 04 01 7d 90 e6 a1 |............}...| -00000010 06 d6 a9 32 e9 ba 42 d5 05 11 e7 69 7c 5e 6e b6 |...2..B....i|^n.| -00000020 ad 51 bc 25 12 89 93 e0 bf 3c 2f ce a8 83 29 0e |.Q.%.....</...).| -00000030 eb 06 89 10 f4 de ce d9 16 6c 95 dc 61 66 84 87 |.........l..af..| -00000040 84 6b 47 77 01 55 79 a2 0d e0 e8 d0 bd 00 7e d7 |.kGw.Uy.......~.| -00000050 34 a4 75 e4 c8 ac e4 a3 4b df 27 52 7a f7 1b 0f |4.u.....K.'Rz...| -00000060 73 af 26 66 2c c9 29 56 b9 e2 1b b8 02 21 80 74 |s.&f,.)V.....!.t| -00000070 db c8 d4 99 31 8f 6c 41 a6 b2 ac 60 82 13 85 08 |....1.lA...`....| -00000080 4d 34 f2 77 ba 22 ec 05 92 9c 9b ca 2d 8e dc 14 |M4.w."......-...| -00000090 03 03 00 01 01 16 03 03 00 40 19 4c 60 51 51 ed |.........@.L`QQ.| -000000a0 03 16 fe 05 a4 88 17 91 f0 0a 50 0d e4 a8 82 9a |..........P.....| -000000b0 4d 4b ef 2a 3d 57 29 60 e7 36 70 9c 41 e2 93 89 |MK.*=W)`.6p.A...| -000000c0 b7 b0 f6 76 fc 19 93 7b ac 8e 39 d1 7c 90 73 62 |...v...{..9.|.sb| -000000d0 88 bf 0b 20 f9 fd 49 b4 d9 3c |... ..I..<| +00000000 16 03 03 00 46 10 00 00 42 41 04 dd 22 68 a1 4e |....F...BA.."h.N| +00000010 04 1b 47 f9 c5 7d 04 1d d8 fe 84 fa be 31 2e a7 |..G..}.......1..| +00000020 f8 e5 b8 14 92 44 99 11 0e 34 97 fc e5 b1 91 cf |.....D...4......| +00000030 a4 d1 3f b4 71 94 c6 06 16 f0 98 c0 3e 05 f9 2f |..?.q.......>../| +00000040 0a 97 78 3d ef dc fa a2 d7 ee 7d 14 03 03 00 01 |..x=......}.....| +00000050 01 16 03 03 00 40 90 bf 7f e9 c9 6e d1 80 f5 12 |.....@.....n....| +00000060 6d c5 b7 c5 15 4b 18 a5 d3 18 1e f8 8c 4d 7e 6d |m....K.......M~m| +00000070 03 60 29 7c 45 7c b2 ca 8c 07 71 70 aa 23 fa 6e |.`)|E|....qp.#.n| +00000080 d9 0b 0a 32 4c 9e e5 00 f9 19 9b b6 8d dc d3 67 |...2L..........g| +00000090 3d 0f bb b8 4b 9e |=...K.| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 f1 df 07 dd 3f |...............?| -00000020 92 27 96 9a 5c 98 4a 3b 39 0b 5d 2e 5f 12 55 11 |.'..\.J;9.]._.U.| -00000030 32 4d 14 39 31 02 1b 02 ee b0 ae 2c 19 8d c2 31 |2M.91......,...1| -00000040 52 cc e9 c3 d6 34 ac 4d 7f e6 6e 17 03 03 00 40 |R....4.M..n....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 a1 6e e5 d1 ca |............n...| +00000020 03 f4 77 dc ec ee 5d f0 22 5e 7f 55 1a 8d ad 45 |..w...]."^.U...E| +00000030 09 f1 3b b2 61 36 dc 3d 2a 1e 1f e5 a7 84 76 a9 |..;.a6.=*.....v.| +00000040 41 5b 86 03 ac 22 18 20 9b a9 29 17 03 03 00 40 |A[...". ..)....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 6b 1e 9a b5 a8 89 3c d0 05 08 cf 81 a7 02 b4 ed |k.....<.........| -00000070 fa 21 e2 15 87 d0 78 ac 4b 8e fc d0 c5 0e b2 5c |.!....x.K......\| -00000080 bb c6 49 2a 80 00 67 93 37 4c a6 38 a7 24 f3 05 |..I*..g.7L.8.$..| +00000060 f5 cb 28 1e b5 bc 82 7f 82 38 54 14 e8 b9 6d 3b |..(......8T...m;| +00000070 bc 99 d6 0e f9 00 96 99 a8 92 2e 86 9d 62 4e 90 |.............bN.| +00000080 27 52 58 45 20 93 90 a1 f3 a8 89 2b e7 21 24 16 |'RXE ......+.!$.| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 50 ea de de b1 ba e4 da b1 d2 3e |.....P.........>| -000000b0 b3 ed 03 2f 8e 30 d5 20 f8 2a 65 d4 4c 1c b9 7f |.../.0. .*e.L...| -000000c0 4c 0c 8f cf 5a |L...Z| +000000a0 00 00 00 00 00 a8 2a ab 8f b0 ce 49 8b fd a5 c9 |......*....I....| +000000b0 11 b2 04 83 18 f3 1d 6c 82 34 1d df dd 2f 45 3b |.......l.4.../E;| +000000c0 27 8a 0f 16 69 |'...i| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM index 6f7e0e40ab1..0ddfe022f22 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM @@ -1,7 +1,7 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 9c 01 00 00 98 03 03 52 cc 57 59 d3 |...........R.WY.| -00000010 91 67 1b de 52 be 25 1d 61 3b 45 29 43 aa 8a e9 |.g..R.%.a;E)C...| -00000020 fc 29 19 d5 59 aa 48 0d 21 8a eb 00 00 04 c0 2f |.)..Y.H.!....../| +00000000 16 03 01 00 9c 01 00 00 98 03 03 53 04 f1 30 73 |...........S..0s| +00000010 a1 ea 8c d2 90 1c c6 d6 0d 3c af 58 21 65 90 25 |.........<.X!e.%| +00000020 5e fa f4 27 22 65 c9 68 90 b9 04 00 00 04 c0 2f |^..'"e.h......./| 00000030 00 ff 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a |.....k..........| 00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............| 00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................| @@ -58,45 +58,36 @@ 000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| 000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| 000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 01 11 0c 00 |n8P)l...........| -00000300 01 0d 03 00 19 85 04 01 39 dc ee 44 17 5e db d7 |........9..D.^..| -00000310 27 af b6 56 d9 b4 43 5a 99 cf aa 31 37 0c 6f 3a |'..V..CZ...17.o:| -00000320 a0 f8 53 c4 74 d1 91 0a 46 f5 38 3b 5c 09 d8 97 |..S.t...F.8;\...| -00000330 dc 4b aa 70 26 48 f2 d6 0b 31 c9 f8 d4 98 43 e1 |.K.p&H...1....C.| -00000340 6c d5 c7 b2 8e 0b 01 e6 b6 00 28 80 7b fc 96 8f |l.........(.{...| -00000350 0d a2 4f b0 79 af dc 61 28 63 33 78 f6 31 39 fd |..O.y..a(c3x.19.| -00000360 8a f4 15 18 11 fe db d5 07 da 2c ed 49 a0 23 bf |..........,.I.#.| -00000370 d0 3a 38 1d 54 ae 1c 7b ea 29 ee d0 38 c1 76 a7 |.:8.T..{.)..8.v.| -00000380 7f 2a f4 ce 1e ac cc 94 79 90 33 04 01 00 80 5f |.*......y.3...._| -00000390 c6 9e 6d 87 97 04 b5 c2 12 73 75 ff a5 40 d0 0f |..m......su..@..| -000003a0 39 74 98 e5 1f 62 4c e8 9a af a0 d4 08 61 d4 53 |9t...bL......a.S| -000003b0 67 ee f6 27 45 1a ee 52 35 7a 5f 5b 54 4a de 9b |g..'E..R5z_[TJ..| -000003c0 fb 9a a2 61 e1 db be b0 08 5d 4f fc b5 5d d3 bc |...a.....]O..]..| -000003d0 c9 49 e2 b9 d8 52 52 79 d1 a3 8e da 7d 35 12 19 |.I...RRy....}5..| -000003e0 45 30 fb fd e7 e2 f4 00 43 78 64 ca 2b 6c 65 28 |E0......Cxd.+le(| -000003f0 8a 8d 83 4f cf 44 9a 19 89 4d 08 d8 85 b3 65 95 |...O.D...M....e.| -00000400 e8 47 4d 86 25 48 09 5c 77 7d 73 0c 6b 22 22 16 |.GM.%H.\w}s.k"".| -00000410 03 03 00 04 0e 00 00 00 |........| +000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 cd 0c 00 |n8P)l...........| +00000300 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| +00000310 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| +00000320 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| +00000330 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| +00000340 41 03 56 6b dc 5a 89 04 01 00 80 a2 54 61 84 29 |A.Vk.Z......Ta.)| +00000350 3e 97 4b 97 9a 9f 5c c0 49 6d 86 d2 79 8e 95 a1 |>.K...\.Im..y...| +00000360 0a 5a 36 73 34 bb 05 73 35 47 e1 2b 5d f3 ef 36 |.Z6s4..s5G.+]..6| +00000370 a8 32 e2 7e ef aa 3f 1f b3 64 60 d4 06 2e 98 e3 |.2.~..?..d`.....| +00000380 11 e2 60 3c d6 20 17 63 b2 6f a0 cd 21 01 2b 4e |..`<. .c.o..!.+N| +00000390 b2 a8 55 04 39 37 5c 6c 71 66 4d a3 eb 1b 83 67 |..U.97\lqfM....g| +000003a0 6b 15 a0 56 9a f1 a2 79 92 29 ce 58 3c 10 4d 65 |k..V...y.).X<.Me| +000003b0 1f 22 e3 ea d8 74 aa 01 7e ca f3 89 23 41 4d bd |."...t..~...#AM.| +000003c0 df 77 4e 59 54 97 74 ad 07 ea c0 16 03 03 00 04 |.wNYT.t.........| +000003d0 0e 00 00 00 |....| >>> Flow 3 (client to server) -00000000 16 03 03 00 8a 10 00 00 86 85 04 01 4e f2 1d 1f |............N...| -00000010 c0 23 cf 00 58 0b 25 ee 6b e1 5f 50 7b c9 15 9d |.#..X.%.k._P{...| -00000020 d9 2f 8a f1 b8 7b 62 d2 6d d0 46 b8 6f 3f 2d 6f |./...{b.m.F.o?-o| -00000030 ba 68 74 7e a3 b5 12 1c 93 d1 0a 13 e1 50 d7 82 |.ht~.........P..| -00000040 1b 4c 54 b5 73 a9 9e 72 80 4e bc 75 17 00 e1 f3 |.LT.s..r.N.u....| -00000050 70 03 80 1f d3 1f 2a 53 52 6a ee 4e 93 f4 10 1c |p.....*SRj.N....| -00000060 2d ff 5f 6c a4 3b fa a1 7f 87 93 5d 76 b3 35 62 |-._l.;.....]v.5b| -00000070 0b 48 41 42 f9 57 65 4a 42 9e 53 7d 2c 09 37 02 |.HAB.WeJB.S},.7.| -00000080 55 bd 6f 0e 4d 05 17 8d c5 df ff 54 da 94 d6 14 |U.o.M......T....| -00000090 03 03 00 01 01 16 03 03 00 28 38 e3 ad 08 8e e3 |.........(8.....| -000000a0 b8 bc 6d a2 15 35 b1 b2 28 47 82 63 30 9e b6 5c |..m..5..(G.c0..\| -000000b0 26 47 38 20 a0 77 e3 b2 38 8f 8b c4 96 ac f4 5c |&G8 .w..8......\| -000000c0 10 9f |..| +00000000 16 03 03 00 46 10 00 00 42 41 04 45 65 ce f7 b9 |....F...BA.Ee...| +00000010 52 e3 fb 13 db 91 f2 65 43 84 57 f5 1a 19 a0 e6 |R......eC.W.....| +00000020 89 2d bb 2c 83 6b 62 f6 6f 1f 26 ae 59 67 bd dc |.-.,.kb.o.&.Yg..| +00000030 c4 9e 0b dc 7d 6e f8 6b 95 8c 61 47 3d cd d1 df |....}n.k..aG=...| +00000040 82 45 30 81 c3 a3 49 5d 85 59 70 14 03 03 00 01 |.E0...I].Yp.....| +00000050 01 16 03 03 00 28 3f aa 85 33 f9 c6 95 a0 56 ff |.....(?..3....V.| +00000060 1c f1 5a ba 6e 41 50 0c ab 92 e1 e2 8e 89 1c f1 |..Z.nAP.........| +00000070 fa 54 1b f1 f5 00 01 12 6d c4 96 78 b6 87 |.T......m..x..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....| -00000010 00 00 00 30 ae 4d 36 49 d1 d6 4d 1a 71 87 eb ed |...0.M6I..M.q...| -00000020 d2 6f 66 3f 25 03 a5 69 04 5d ca e6 71 eb c2 06 |.of?%..i.]..q...| -00000030 b4 15 b7 17 03 03 00 25 00 00 00 00 00 00 00 01 |.......%........| -00000040 8d a6 27 08 34 77 a2 a7 f5 e6 c3 ca 49 25 db 9a |..'.4w......I%..| -00000050 19 44 42 d1 0b c1 3a d6 73 b2 11 df 52 15 03 03 |.DB...:.s...R...| -00000060 00 1a 00 00 00 00 00 00 00 02 42 63 43 f7 98 69 |..........BcC..i| -00000070 d9 2b 38 6b 88 9d bf a2 8a 31 5d 54 |.+8k.....1]T| +00000010 00 00 00 94 5c be 46 05 d6 d0 b0 3a 56 dc 2c 10 |....\.F....:V.,.| +00000020 0f 6f 5d 33 33 7f a5 4e 74 84 bf 63 87 c4 f4 49 |.o]33..Nt..c...I| +00000030 bc 6b ab 17 03 03 00 25 00 00 00 00 00 00 00 01 |.k.....%........| +00000040 7e 4f f9 ae ae fe 6b a0 4a f8 0f 0b b4 b6 65 b6 |~O....k.J.....e.| +00000050 be 24 5f 94 6d d1 db 54 11 07 b9 ce 01 15 03 03 |.$_.m..T........| +00000060 00 1a 00 00 00 00 00 00 00 02 a8 1c d6 62 ac fd |.............b..| +00000070 77 ba 23 92 5d 34 f1 17 c7 e1 1c 99 |w.#.]4......| diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go index 40156a0013b..d50e1202924 100644 --- a/libgo/go/crypto/tls/tls.go +++ b/libgo/go/crypto/tls/tls.go @@ -15,6 +15,7 @@ import ( "io/ioutil" "net" "strings" + "time" ) // Server returns a new TLS server side connection @@ -27,7 +28,7 @@ func Server(conn net.Conn, config *Config) *Conn { // Client returns a new TLS client side connection // using conn as the underlying transport. -// The config cannot be nil: users must set either ServerHostname or +// The config cannot be nil: users must set either ServerName or // InsecureSkipVerify in the config. func Client(conn net.Conn, config *Config) *Conn { return &Conn{conn: conn, config: config, isClient: true} @@ -76,24 +77,51 @@ func Listen(network, laddr string, config *Config) (net.Listener, error) { return NewListener(l, config), nil } -// Dial connects to the given network address using net.Dial -// and then initiates a TLS handshake, returning the resulting -// TLS connection. -// Dial interprets a nil configuration as equivalent to -// the zero configuration; see the documentation of Config -// for the defaults. -func Dial(network, addr string, config *Config) (*Conn, error) { - raddr := addr - c, err := net.Dial(network, raddr) +type timeoutError struct{} + +func (timeoutError) Error() string { return "tls: DialWithDialer timed out" } +func (timeoutError) Timeout() bool { return true } +func (timeoutError) Temporary() bool { return true } + +// DialWithDialer connects to the given network address using dialer.Dial and +// then initiates a TLS handshake, returning the resulting TLS connection. Any +// timeout or deadline given in the dialer apply to connection and TLS +// handshake as a whole. +// +// DialWithDialer interprets a nil configuration as equivalent to the zero +// configuration; see the documentation of Config for the defaults. +func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + // We want the Timeout and Deadline values from dialer to cover the + // whole process: TCP connection and TLS handshake. This means that we + // also need to start our own timers now. + timeout := dialer.Timeout + + if !dialer.Deadline.IsZero() { + deadlineTimeout := dialer.Deadline.Sub(time.Now()) + if timeout == 0 || deadlineTimeout < timeout { + timeout = deadlineTimeout + } + } + + var errChannel chan error + + if timeout != 0 { + errChannel = make(chan error, 2) + time.AfterFunc(timeout, func() { + errChannel <- timeoutError{} + }) + } + + rawConn, err := dialer.Dial(network, addr) if err != nil { return nil, err } - colonPos := strings.LastIndex(raddr, ":") + colonPos := strings.LastIndex(addr, ":") if colonPos == -1 { - colonPos = len(raddr) + colonPos = len(addr) } - hostname := raddr[:colonPos] + hostname := addr[:colonPos] if config == nil { config = defaultConfig() @@ -106,14 +134,37 @@ func Dial(network, addr string, config *Config) (*Conn, error) { c.ServerName = hostname config = &c } - conn := Client(c, config) - if err = conn.Handshake(); err != nil { - c.Close() + + conn := Client(rawConn, config) + + if timeout == 0 { + err = conn.Handshake() + } else { + go func() { + errChannel <- conn.Handshake() + }() + + err = <-errChannel + } + + if err != nil { + rawConn.Close() return nil, err } + return conn, nil } +// Dial connects to the given network address using net.Dial +// and then initiates a TLS handshake, returning the resulting +// TLS connection. +// Dial interprets a nil configuration as equivalent to +// the zero configuration; see the documentation of Config +// for the defaults. +func Dial(network, addr string, config *Config) (*Conn, error) { + return DialWithDialer(new(net.Dialer), network, addr, config) +} + // LoadX509KeyPair reads and parses a public/private key pair from a pair of // files. The files must contain PEM encoded data. func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) { diff --git a/libgo/go/crypto/tls/tls_test.go b/libgo/go/crypto/tls/tls_test.go index 38229014cd6..f8c94ff35d4 100644 --- a/libgo/go/crypto/tls/tls_test.go +++ b/libgo/go/crypto/tls/tls_test.go @@ -5,7 +5,12 @@ package tls import ( + "fmt" + "io" + "net" + "strings" "testing" + "time" ) var rsaCertPEM = `-----BEGIN CERTIFICATE----- @@ -105,3 +110,128 @@ func TestX509MixedKeyPair(t *testing.T) { t.Error("Load of ECDSA certificate succeeded with RSA private key") } } + +func newLocalListener(t *testing.T) net.Listener { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + ln, err = net.Listen("tcp6", "[::1]:0") + } + if err != nil { + t.Fatal(err) + } + return ln +} + +func TestDialTimeout(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + listener := newLocalListener(t) + + addr := listener.Addr().String() + defer listener.Close() + + complete := make(chan bool) + defer close(complete) + + go func() { + conn, err := listener.Accept() + if err != nil { + t.Error(err) + return + } + <-complete + conn.Close() + }() + + dialer := &net.Dialer{ + Timeout: 10 * time.Millisecond, + } + + var err error + if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil { + t.Fatal("DialWithTimeout completed successfully") + } + + if !strings.Contains(err.Error(), "timed out") { + t.Errorf("resulting error not a timeout: %s", err) + } +} + +// tests that Conn.Read returns (non-zero, io.EOF) instead of +// (non-zero, nil) when a Close (alertCloseNotify) is sitting right +// behind the application data in the buffer. +func TestConnReadNonzeroAndEOF(t *testing.T) { + // This test is racy: it assumes that after a write to a + // localhost TCP connection, the peer TCP connection can + // immediately read it. Because it's racy, we skip this test + // in short mode, and then retry it several times with an + // increasing sleep in between our final write (via srv.Close + // below) and the following read. + if testing.Short() { + t.Skip("skipping in short mode") + } + var err error + for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 { + if err = testConnReadNonzeroAndEOF(t, delay); err == nil { + return + } + } + t.Error(err) +} + +func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error { + ln := newLocalListener(t) + defer ln.Close() + + srvCh := make(chan *Conn, 1) + var serr error + go func() { + sconn, err := ln.Accept() + if err != nil { + serr = err + srvCh <- nil + return + } + serverConfig := *testConfig + srv := Server(sconn, &serverConfig) + if err := srv.Handshake(); err != nil { + serr = fmt.Errorf("handshake: %v", err) + srvCh <- nil + return + } + srvCh <- srv + }() + + clientConfig := *testConfig + conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + srv := <-srvCh + if srv == nil { + return serr + } + + buf := make([]byte, 6) + + srv.Write([]byte("foobar")) + n, err := conn.Read(buf) + if n != 6 || err != nil || string(buf) != "foobar" { + return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf) + } + + srv.Write([]byte("abcdef")) + srv.Close() + time.Sleep(delay) + n, err = conn.Read(buf) + if n != 6 || string(buf) != "abcdef" { + return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf) + } + if err != io.EOF { + return fmt.Errorf("Second Read error = %v; want io.EOF", err) + } + return nil +} diff --git a/libgo/go/crypto/x509/root_unix.go b/libgo/go/crypto/x509/root_unix.go index a5bd19e8216..11ad3c440d2 100644 --- a/libgo/go/crypto/x509/root_unix.go +++ b/libgo/go/crypto/x509/root_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build dragonfly freebsd linux openbsd netbsd solaris +// +build dragonfly freebsd linux nacl netbsd openbsd solaris package x509 diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index ba6c13d4510..96b9d9b420b 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -31,8 +31,8 @@ type verifyTest struct { var verifyTests = []verifyTest{ { leaf: googleLeaf, - intermediates: []string{thawteIntermediate}, - currentTime: 1302726541, + intermediates: []string{giag2Intermediate}, + currentTime: 1395785200, dnsName: "www.google.com", testSystemRootsError: true, @@ -42,39 +42,39 @@ var verifyTests = []verifyTest{ }, { leaf: googleLeaf, - intermediates: []string{thawteIntermediate}, - roots: []string{verisignRoot}, - currentTime: 1302726541, + intermediates: []string{giag2Intermediate}, + roots: []string{geoTrustRoot}, + currentTime: 1395785200, dnsName: "www.google.com", expectedChains: [][]string{ - {"Google", "Thawte", "VeriSign"}, + {"Google", "Google Internet Authority", "GeoTrust"}, }, }, { leaf: googleLeaf, - intermediates: []string{thawteIntermediate}, - roots: []string{verisignRoot}, - currentTime: 1302726541, + intermediates: []string{giag2Intermediate}, + roots: []string{geoTrustRoot}, + currentTime: 1395785200, dnsName: "WwW.GooGLE.coM", expectedChains: [][]string{ - {"Google", "Thawte", "VeriSign"}, + {"Google", "Google Internet Authority", "GeoTrust"}, }, }, { leaf: googleLeaf, - intermediates: []string{thawteIntermediate}, - roots: []string{verisignRoot}, - currentTime: 1302726541, + intermediates: []string{giag2Intermediate}, + roots: []string{geoTrustRoot}, + currentTime: 1395785200, dnsName: "www.example.com", errorCallback: expectHostnameError, }, { leaf: googleLeaf, - intermediates: []string{thawteIntermediate}, - roots: []string{verisignRoot}, + intermediates: []string{giag2Intermediate}, + roots: []string{geoTrustRoot}, currentTime: 1, dnsName: "www.example.com", @@ -82,8 +82,8 @@ var verifyTests = []verifyTest{ }, { leaf: googleLeaf, - roots: []string{verisignRoot}, - currentTime: 1302726541, + roots: []string{geoTrustRoot}, + currentTime: 1395785200, dnsName: "www.google.com", // Skip when using systemVerify, since Windows @@ -93,14 +93,22 @@ var verifyTests = []verifyTest{ }, { leaf: googleLeaf, - intermediates: []string{verisignRoot, thawteIntermediate}, - roots: []string{verisignRoot}, - currentTime: 1302726541, + intermediates: []string{geoTrustRoot, giag2Intermediate}, + roots: []string{geoTrustRoot}, + currentTime: 1395785200, dnsName: "www.google.com", expectedChains: [][]string{ - {"Google", "Thawte", "VeriSign"}, + {"Google", "Google Internet Authority", "GeoTrust"}, + // TODO(agl): this is ok, but it would be nice if the + // chain building didn't visit the same SPKI + // twice. + {"Google", "Google Internet Authority", "GeoTrust", "GeoTrust"}, }, + // CAPI doesn't build the chain with the duplicated GeoTrust + // entry so the results don't match. Thus we skip this test + // until that's fixed. + systemSkip: true, }, { leaf: dnssecExpLeaf, @@ -128,9 +136,9 @@ var verifyTests = []verifyTest{ }, { leaf: googleLeafWithInvalidHash, - intermediates: []string{thawteIntermediate}, - roots: []string{verisignRoot}, - currentTime: 1302726541, + intermediates: []string{giag2Intermediate}, + roots: []string{geoTrustRoot}, + currentTime: 1395785200, dnsName: "www.google.com", // The specific error message may not occur when using system @@ -201,6 +209,24 @@ var verifyTests = []verifyTest{ }, }, }, + { + // Check that SHA-384 intermediates (which are popping up) + // work. + leaf: moipLeafCert, + intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority}, + roots: []string{addTrustRoot}, + currentTime: 1397502195, + dnsName: "api.moip.com.br", + + expectedChains: [][]string{ + { + "api.moip.com.br", + "COMODO RSA Extended Validation Secure Server CA", + "COMODO RSA Certification Authority", + "AddTrust External CA Root", + }, + }, + }, } func expectHostnameError(t *testing.T, i int, err error) (ok bool) { @@ -385,84 +411,111 @@ func nameToKey(name *pkix.Name) string { return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName } -const verisignRoot = `-----BEGIN CERTIFICATE----- -MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE -BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is -I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G -CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do -lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc -AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k +const geoTrustRoot = `-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== -----END CERTIFICATE----- ` -const thawteIntermediate = `-----BEGIN CERTIFICATE----- -MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi -bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw -MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh -d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD -QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx -PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g -5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo -3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG -A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX -BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov -L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG -AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF -BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB -BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc -q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR -bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv +const giag2Intermediate = `-----BEGIN CERTIFICATE----- +MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG +EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy +bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP +VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv +h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE +ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ +EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC +DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7 +qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD +VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g +K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI +KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n +ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB +BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY +/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/ +zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza +HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto +WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6 +yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx -----END CERTIFICATE----- ` const googleLeaf = `-----BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM -MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg -THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x -MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh -MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw -FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC -gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN -gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L -05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM -BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl -LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF -BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw -Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0 -ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF -AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5 -u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6 -z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw== ------END CERTIFICATE-----` +MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE +BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl +cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw +WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN +TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3 +Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe +m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6 +jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q +fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4 +NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ +0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI +dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI +KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE +XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0 +MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G +A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud +IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW +eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB +RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj +5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf +tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+ +orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi +8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA +Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX +-----END CERTIFICATE----- +` // googleLeafWithInvalidHash is the same as googleLeaf, but the signature // algorithm in the certificate contains a nonsense OID. const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BATIFADBM -MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg -THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x -MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh -MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw -FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC -gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN -gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L -05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM -BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl -LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF -BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw -Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0 -ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAVAF -AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5 -u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6 -z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw== ------END CERTIFICATE-----` +MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAWAFBQAwSTELMAkGA1UE +BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl +cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw +WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN +TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3 +Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe +m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6 +jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q +fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4 +NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ +0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI +dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI +KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE +XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0 +MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G +A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud +IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW +eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB +RzIuY3JsMA0GCSqGSIb3DQFgBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj +5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf +tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+ +orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi +8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA +Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX +-----END CERTIFICATE----- +` const dnssecExpLeaf = `-----BEGIN CERTIFICATE----- MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ @@ -936,3 +989,135 @@ AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE-----` + +var moipLeafCert = `-----BEGIN CERTIFICATE----- +MIIGQDCCBSigAwIBAgIRAPe/cwh7CUWizo8mYSDavLIwDQYJKoZIhvcNAQELBQAw +gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD +VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl +ciBDQTAeFw0xMzA4MTUwMDAwMDBaFw0xNDA4MTUyMzU5NTlaMIIBQjEXMBUGA1UE +BRMOMDg3MTg0MzEwMDAxMDgxEzARBgsrBgEEAYI3PAIBAxMCQlIxGjAYBgsrBgEE +AYI3PAIBAhMJU2FvIFBhdWxvMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlv +bjELMAkGA1UEBhMCQlIxETAPBgNVBBETCDAxNDUyMDAwMRIwEAYDVQQIEwlTYW8g +UGF1bG8xEjAQBgNVBAcTCVNhbyBQYXVsbzEtMCsGA1UECRMkQXZlbmlkYSBCcmln +YWRlaXJvIEZhcmlhIExpbWEgLCAyOTI3MR0wGwYDVQQKExRNb2lwIFBhZ2FtZW50 +b3MgUy5BLjENMAsGA1UECxMETU9JUDEYMBYGA1UECxMPU1NMIEJsaW5kYWRvIEVW +MRgwFgYDVQQDEw9hcGkubW9pcC5jb20uYnIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDN0b9x6TrXXA9hPCF8/NjqGJ++2D4LO4ZiMFTjs0VwpXy2Y1Oe +s74/HuiLGnAHxTmAtV7IpZMibiOcTxcnDYp9oEWkf+gR+hZvwFZwyOBC7wyb3SR3 +UvV0N1ZbEVRYpN9kuX/3vjDghjDmzzBwu8a/T+y5JTym5uiJlngVAWyh/RjtIvYi ++NVkQMbyVlPGkoCe6c30pH8DKYuUCZU6DHjUsPTX3jAskqbhDSAnclX9iX0p2bmw +KVBc+5Vh/2geyzDuquF0w+mNIYdU5h7uXvlmJnf3d2Cext5dxdL8/jezD3U0dAqI +pYSKERbyxSkJWxdvRlhdpM9YXMJcpc88xNp1AgMBAAGjggHcMIIB2DAfBgNVHSME +GDAWgBQ52v/KKBSKqHQTCLnkDqnS+n6daTAdBgNVHQ4EFgQU/lXuOa7DMExzZjRj +LQWcMWGZY7swDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw +FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQUB +MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMFYG +A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT +QUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBhwYIKwYBBQUH +AQEEezB5MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01P +RE9SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYB +BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAvBgNVHREEKDAmgg9hcGku +bW9pcC5jb20uYnKCE3d3dy5hcGkubW9pcC5jb20uYnIwDQYJKoZIhvcNAQELBQAD +ggEBAFoTmPlaDcf+nudhjXHwud8g7/LRyA8ucb+3/vfmgbn7FUc1eprF5sJS1mA+ +pbiTyXw4IxcJq2KUj0Nw3IPOe9k84mzh+XMmdCKH+QK3NWkE9Udz+VpBOBc0dlqC +1RH5umStYDmuZg/8/r652eeQ5kUDcJyADfpKWBgDPYaGtwzKVT4h3Aok9SLXRHx6 +z/gOaMjEDMarMCMw4VUIG1pvNraZrG5oTaALPaIXXpd8VqbQYPudYJ6fR5eY3FeW +H/ofbYFdRcuD26MfBFWE9VGGral9Fgo8sEHffho+UWhgApuQV4/l5fMzxB5YBXyQ +jhuy8PqqZS9OuLilTeLu4a8z2JI= +-----END CERTIFICATE-----` + +var comodoIntermediateSHA384 = `-----BEGIN CERTIFICATE----- +MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy +MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg +VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf +CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj +vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA +xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6 +WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg +iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j +BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI +ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G +A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j +b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr +BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t +L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz +cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R +AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk +jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk +1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i +teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o +fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA +KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e +ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9 +XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA +tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2 +jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn +pLwltum95OmYdBbxN4SBB7SC +-----END CERTIFICATE-----` + +const comodoRSAAuthority = `-----BEGIN CERTIFICATE----- +MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk +ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF +eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow +gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD +VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw +AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6 +2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr +ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt +4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq +m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/ +vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT +8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE +IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO +KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO +GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/ +s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g +JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD +AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9 +MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy +bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6 +Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ +zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj +Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY +Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5 +B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx +PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR +pu/xO28QOG8= +-----END CERTIFICATE-----` + +const addTrustRoot = `-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE-----` diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 3570e02359e..c347fb384dc 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -14,6 +14,7 @@ import ( "crypto/rsa" "crypto/sha1" _ "crypto/sha256" + _ "crypto/sha512" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index d158a9d8631..41d186b5b64 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -22,6 +22,7 @@ import ( "net" "os/exec" "reflect" + "runtime" "testing" "time" ) @@ -395,7 +396,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) { } if cert.SignatureAlgorithm != test.sigAlgo { - t.Errorf("%s: SignatureAlgorithm wasn't copied from template. Got %s, want %s", test.name, cert.SignatureAlgorithm, test.sigAlgo) + t.Errorf("%s: SignatureAlgorithm wasn't copied from template. Got %v, want %v", test.name, cert.SignatureAlgorithm, test.sigAlgo) } if !reflect.DeepEqual(cert.ExtKeyUsage, testExtKeyUsage) { @@ -728,6 +729,10 @@ func TestParsePEMCRL(t *testing.T) { func TestImports(t *testing.T) { t.Skip("gccgo does not have a go command") + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil { t.Errorf("failed to run x509_test_import.go: %s", err) } diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go index 0828e63c656..eca25f29a0a 100644 --- a/libgo/go/database/sql/driver/driver.go +++ b/libgo/go/database/sql/driver/driver.go @@ -134,7 +134,7 @@ type Stmt interface { // as an INSERT or UPDATE. Exec(args []Value) (Result, error) - // Exec executes a query that may return rows, such as a + // Query executes a query that may return rows, such as a // SELECT. Query(args []Value) (Rows, error) } diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go index 4f86d24b2e5..765b80c60a2 100644 --- a/libgo/go/database/sql/sql.go +++ b/libgo/go/database/sql/sql.go @@ -181,7 +181,8 @@ type Scanner interface { // defers this error until a Scan. var ErrNoRows = errors.New("sql: no rows in result set") -// DB is a database handle. It's safe for concurrent use by multiple +// DB is a database handle representing a pool of zero or more +// underlying connections. It's safe for concurrent use by multiple // goroutines. // // The sql package creates and frees connections automatically; it @@ -405,7 +406,7 @@ func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error { // This value should be larger than the maximum typical value // used for db.maxOpen. If maxOpen is significantly larger than // connectionRequestQueueSize then it is possible for ALL calls into the *DB -// to block until the connectionOpener can satify the backlog of requests. +// to block until the connectionOpener can satisfy the backlog of requests. var connectionRequestQueueSize = 1000000 // Open opens a database specified by its database driver name and a @@ -420,6 +421,11 @@ var connectionRequestQueueSize = 1000000 // Open may just validate its arguments without creating a connection // to the database. To verify that the data source name is valid, call // Ping. +// +// The returned DB is safe for concurrent use by multiple goroutines +// and maintains its own pool of idle connections. Thus, the Open +// function should be called just once. It is rarely necessary to +// close a DB. func Open(driverName, dataSourceName string) (*DB, error) { driveri, ok := drivers[driverName] if !ok { @@ -452,6 +458,9 @@ func (db *DB) Ping() error { } // Close closes the database, releasing any open resources. +// +// It is rare to Close a DB, as the DB handle is meant to be +// long-lived and shared between many goroutines. func (db *DB) Close() error { db.mu.Lock() if db.closed { // Make DB.Close idempotent @@ -652,13 +661,16 @@ func (db *DB) conn() (*driverConn, error) { return conn, nil } + db.numOpen++ // optimistically db.mu.Unlock() ci, err := db.driver.Open(db.dsn) if err != nil { + db.mu.Lock() + db.numOpen-- // correct for earlier optimism + db.mu.Unlock() return nil, err } db.mu.Lock() - db.numOpen++ dc := &driverConn{ db: db, ci: ci, @@ -778,7 +790,7 @@ func (db *DB) putConn(dc *driverConn, err error) { // connection limit will not be exceeded. // If err != nil, the value of dc is ignored. // If err == nil, then dc must not equal nil. -// If a connRequest was fullfilled or the *driverConn was placed in the +// If a connRequest was fulfilled or the *driverConn was placed in the // freeConn list, then true is returned, otherwise false is returned. func (db *DB) putConnDBLocked(dc *driverConn, err error) bool { if db.connRequests.Len() > 0 { @@ -1494,6 +1506,7 @@ func (s *Stmt) finalClose() error { // // rows, err := db.Query("SELECT ...") // ... +// defer rows.Close() // for rows.Next() { // var id int // var name string diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go index a0a20df6f83..7971f149174 100644 --- a/libgo/go/database/sql/sql_test.go +++ b/libgo/go/database/sql/sql_test.go @@ -461,7 +461,7 @@ func TestTxStmt(t *testing.T) { } // Issue: http://golang.org/issue/2784 -// This test didn't fail before because we got luckly with the fakedb driver. +// This test didn't fail before because we got lucky with the fakedb driver. // It was failing, and now not, in github.com/bradfitz/go-sql-test func TestTxQuery(t *testing.T) { db := newTestDB(t, "") diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go index 2aa0c270ff2..6cc6bc937a5 100644 --- a/libgo/go/debug/dwarf/const.go +++ b/libgo/go/debug/dwarf/const.go @@ -212,6 +212,10 @@ const ( formExprloc format = 0x18 formFlagPresent format = 0x19 formRefSig8 format = 0x20 + // Extensions for multi-file compression (.dwz) + // http://www.dwarfstd.org/ShowIssue.php?issue=120604.1 + formGnuRefAlt format = 0x1f20 + formGnuStrpAlt format = 0x1f21 ) // A Tag is the classification (the type) of an Entry. diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go index 1772221633f..b6ba8c0d1c3 100644 --- a/libgo/go/debug/dwarf/entry.go +++ b/libgo/go/debug/dwarf/entry.go @@ -241,10 +241,10 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { // lineptr, loclistptr, macptr, rangelistptr // New in DWARF 4, but clang can generate them with -gdwarf-2. // Section reference, replacing use of formData4 and formData8. - case formSecOffset: + case formSecOffset, formGnuRefAlt, formGnuStrpAlt: is64, known := b.format.dwarf64() if !known { - b.error("unknown size for DW_FORM_sec_offset") + b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16)) } else if is64 { val = int64(b.uint64()) } else { diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go index 03e42b03465..d622dae2af7 100644 --- a/libgo/go/debug/elf/elf.go +++ b/libgo/go/debug/elf/elf.go @@ -517,7 +517,7 @@ const ( DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */ DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */ DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */ - DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */ + DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of termination functions. */ DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */ DT_FLAGS DynTag = 30 /* Object specific flag values. */ DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go index a98b469b330..38269aaf4ab 100644 --- a/libgo/go/debug/elf/file.go +++ b/libgo/go/debug/elf/file.go @@ -522,13 +522,17 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error { if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { return f.applyRelocationsAMD64(dst, rels) } + if f.Class == ELFCLASS32 && f.Machine == EM_386 { + return f.applyRelocations386(dst, rels) + } return errors.New("not implemented") } func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { - if len(rels)%Sym64Size != 0 { - return errors.New("length of relocation section is not a multiple of Sym64Size") + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") } symbols, _, err := f.getSymbols(SHT_SYMTAB) @@ -570,6 +574,43 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { return nil } +func (f *File) applyRelocations386(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_386(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + if t == R_386_32 { + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + func (f *File) DWARF() (*dwarf.Data, error) { // There are many other DWARF sections, but these // are the required ones, and the debug/dwarf package @@ -603,6 +644,19 @@ func (f *File) DWARF() (*dwarf.Data, error) { } } + // When using clang we need to process relocations even for 386. + rel := f.Section(".rel.debug_info") + if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 { + data, err := rel.Data() + if err != nil { + return nil, err + } + err = f.applyRelocations(dat[1], data) + if err != nil { + return nil, err + } + } + abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] d, err := dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) if err != nil { diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go index 38b5f9e7075..7f88a54bcd6 100644 --- a/libgo/go/debug/elf/file_test.go +++ b/libgo/go/debug/elf/file_test.go @@ -261,6 +261,12 @@ var relocationTests = []relocationTest{ }, }, { + "testdata/go-relocation-test-clang-x86.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}}, + }, + }, + { "testdata/gcc-amd64-openbsd-debug-with-rela.obj", []relocationTestEntry{ {203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}}, diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-clang-x86.obj b/libgo/go/debug/elf/testdata/go-relocation-test-clang-x86.obj Binary files differnew file mode 100644 index 00000000000..e909cf4e6e1 --- /dev/null +++ b/libgo/go/debug/elf/testdata/go-relocation-test-clang-x86.obj diff --git a/libgo/go/debug/goobj/read.go b/libgo/go/debug/goobj/read.go deleted file mode 100644 index f65abb6c273..00000000000 --- a/libgo/go/debug/goobj/read.go +++ /dev/null @@ -1,655 +0,0 @@ -// Copyright 2013 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. - -// Package goobj implements reading of Go object files and archives. -// -// TODO(rsc): Decide where this package should live. (golang.org/issue/6932) -// TODO(rsc): Decide the appropriate integer types for various fields. -// TODO(rsc): Write tests. (File format still up in the air a little.) -package goobj - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "strconv" - "strings" -) - -// A SymKind describes the kind of memory represented by a symbol. -type SymKind int - -// This list is taken from include/link.h. - -// Defined SymKind values. -// TODO(rsc): Give idiomatic Go names. -// TODO(rsc): Reduce the number of symbol types in the object files. -const ( - _ SymKind = iota - - // readonly, executable - STEXT - SELFRXSECT - - // readonly, non-executable - STYPE - SSTRING - SGOSTRING - SGOFUNC - SRODATA - SFUNCTAB - STYPELINK - SSYMTAB // TODO: move to unmapped section - SPCLNTAB - SELFROSECT - - // writable, non-executable - SMACHOPLT - SELFSECT - SMACHO // Mach-O __nl_symbol_ptr - SMACHOGOT - SNOPTRDATA - SINITARR - SDATA - SWINDOWS - SBSS - SNOPTRBSS - STLSBSS - - // not mapped - SXREF - SMACHOSYMSTR - SMACHOSYMTAB - SMACHOINDIRECTPLT - SMACHOINDIRECTGOT - SFILE - SFILEPATH - SCONST - SDYNIMPORT - SHOSTOBJ -) - -var symKindStrings = []string{ - SBSS: "SBSS", - SCONST: "SCONST", - SDATA: "SDATA", - SDYNIMPORT: "SDYNIMPORT", - SELFROSECT: "SELFROSECT", - SELFRXSECT: "SELFRXSECT", - SELFSECT: "SELFSECT", - SFILE: "SFILE", - SFILEPATH: "SFILEPATH", - SFUNCTAB: "SFUNCTAB", - SGOFUNC: "SGOFUNC", - SGOSTRING: "SGOSTRING", - SHOSTOBJ: "SHOSTOBJ", - SINITARR: "SINITARR", - SMACHO: "SMACHO", - SMACHOGOT: "SMACHOGOT", - SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT", - SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT", - SMACHOPLT: "SMACHOPLT", - SMACHOSYMSTR: "SMACHOSYMSTR", - SMACHOSYMTAB: "SMACHOSYMTAB", - SNOPTRBSS: "SNOPTRBSS", - SNOPTRDATA: "SNOPTRDATA", - SPCLNTAB: "SPCLNTAB", - SRODATA: "SRODATA", - SSTRING: "SSTRING", - SSYMTAB: "SSYMTAB", - STEXT: "STEXT", - STLSBSS: "STLSBSS", - STYPE: "STYPE", - STYPELINK: "STYPELINK", - SWINDOWS: "SWINDOWS", - SXREF: "SXREF", -} - -func (k SymKind) String() string { - if k < 0 || int(k) >= len(symKindStrings) { - return fmt.Sprintf("SymKind(%d)", k) - } - return symKindStrings[k] -} - -// A Sym is a named symbol in an object file. -type Sym struct { - SymID // symbol identifier (name and version) - Kind SymKind // kind of symbol - DupOK bool // are duplicate definitions okay? - Size int // size of corresponding data - Type SymID // symbol for Go type information - Data Data // memory image of symbol - Reloc []Reloc // relocations to apply to Data - Func *Func // additional data for functions -} - -// A SymID - the combination of Name and Version - uniquely identifies -// a symbol within a package. -type SymID struct { - // Name is the name of a symbol. - Name string - - // Version is zero for symbols with global visibility. - // Symbols with only file visibility (such as file-level static - // declarations in C) have a non-zero version distinguising - // a symbol in one file from a symbol of the same name - // in another file - Version int -} - -func (s SymID) String() string { - if s.Version == 0 { - return s.Name - } - return fmt.Sprintf("%s<%d>", s.Name, s.Version) -} - -// A Data is a reference to data stored in an object file. -// It records the offset and size of the data, so that a client can -// read the data only if necessary. -type Data struct { - Offset int64 - Size int64 -} - -// A Reloc describes a relocation applied to a memory image to refer -// to an address within a particular symbol. -type Reloc struct { - // The bytes at [Offset, Offset+Size) within the memory image - // should be updated to refer to the address Add bytes after the start - // of the symbol Sym. - Offset int - Size int - Sym SymID - Add int - - // The Type records the form of address expected in the bytes - // described by the previous fields: absolute, PC-relative, and so on. - // TODO(rsc): The interpretation of Type is not exposed by this package. - Type int -} - -// A Var describes a variable in a function stack frame: a declared -// local variable, an input argument, or an output result. -type Var struct { - // The combination of Name, Kind, and Offset uniquely - // identifies a variable in a function stack frame. - // Using fewer of these - in particular, using only Name - does not. - Name string // Name of variable. - Kind int // TODO(rsc): Define meaning. - Offset int // Frame offset. TODO(rsc): Define meaning. - - Type SymID // Go type for variable. -} - -// Func contains additional per-symbol information specific to functions. -type Func struct { - Args int // size in bytes of of argument frame: inputs and outputs - Frame int // size in bytes of local variable frame - Var []Var // detail about local variables - PCSP Data // PC → SP offset map - PCFile Data // PC → file number map (index into File) - PCLine Data // PC → line number map - PCData []Data // PC → runtime support data map - FuncData []FuncData // non-PC-specific runtime support data - File []string // paths indexed by PCFile -} - -// TODO: Add PCData []byte and PCDataIter (similar to liblink). - -// A FuncData is a single function-specific data value. -type FuncData struct { - Sym SymID // symbol holding data - Offset int64 // offset into symbol for funcdata pointer -} - -// A Package is a parsed Go object file or archive defining a Go package. -type Package struct { - ImportPath string // import path denoting this package - Imports []string // packages imported by this package - Syms []*Sym // symbols defined by this package - MaxVersion int // maximum Version in any SymID in Syms -} - -var ( - archiveHeader = []byte("!<arch>\n") - archiveMagic = []byte("`\n") - goobjHeader = []byte("go objec") // truncated to size of archiveHeader - - errCorruptArchive = errors.New("corrupt archive") - errTruncatedArchive = errors.New("truncated archive") - errNotArchive = errors.New("unrecognized archive format") - - errCorruptObject = errors.New("corrupt object file") - errTruncatedObject = errors.New("truncated object file") - errNotObject = errors.New("unrecognized object file format") -) - -// An objReader is an object file reader. -type objReader struct { - p *Package - b *bufio.Reader - f io.ReadSeeker - err error - offset int64 - limit int64 - tmp [256]byte - pkg string - pkgprefix string -} - -// importPathToPrefix returns the prefix that will be used in the -// final symbol table for the given import path. -// We escape '%', '"', all control characters and non-ASCII bytes, -// and any '.' after the final slash. -// -// See ../../../cmd/ld/lib.c:/^pathtoprefix and -// ../../../cmd/gc/subr.c:/^pathtoprefix. -func importPathToPrefix(s string) string { - // find index of last slash, if any, or else -1. - // used for determining whether an index is after the last slash. - slash := strings.LastIndex(s, "/") - - // check for chars that need escaping - n := 0 - for r := 0; r < len(s); r++ { - if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { - n++ - } - } - - // quick exit - if n == 0 { - return s - } - - // escape - const hex = "0123456789abcdef" - p := make([]byte, 0, len(s)+2*n) - for r := 0; r < len(s); r++ { - if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { - p = append(p, '%', hex[c>>4], hex[c&0xF]) - } else { - p = append(p, c) - } - } - - return string(p) -} - -// init initializes r to read package p from f. -func (r *objReader) init(f io.ReadSeeker, p *Package) { - r.f = f - r.p = p - r.offset, _ = f.Seek(0, 1) - r.limit, _ = f.Seek(0, 2) - f.Seek(r.offset, 0) - r.b = bufio.NewReader(f) - r.pkgprefix = importPathToPrefix(p.ImportPath) + "." -} - -// error records that an error occurred. -// It returns only the first error, so that an error -// caused by an earlier error does not discard information -// about the earlier error. -func (r *objReader) error(err error) error { - if r.err == nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - r.err = err - } - // panic("corrupt") // useful for debugging - return r.err -} - -// readByte reads and returns a byte from the input file. -// On I/O error or EOF, it records the error but returns byte 0. -// A sequence of 0 bytes will eventually terminate any -// parsing state in the object file. In particular, it ends the -// reading of a varint. -func (r *objReader) readByte() byte { - if r.err != nil { - return 0 - } - if r.offset >= r.limit { - r.error(io.ErrUnexpectedEOF) - return 0 - } - b, err := r.b.ReadByte() - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - r.error(err) - b = 0 - } else { - r.offset++ - } - return b -} - -// read reads exactly len(b) bytes from the input file. -// If an error occurs, read returns the error but also -// records it, so it is safe for callers to ignore the result -// as long as delaying the report is not a problem. -func (r *objReader) readFull(b []byte) error { - if r.err != nil { - return r.err - } - if r.offset+int64(len(b)) > r.limit { - return r.error(io.ErrUnexpectedEOF) - } - n, err := io.ReadFull(r.b, b) - r.offset += int64(n) - if err != nil { - return r.error(err) - } - return nil -} - -// readInt reads a zigzag varint from the input file. -func (r *objReader) readInt() int { - var u uint64 - - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - r.error(errCorruptObject) - return 0 - } - c := r.readByte() - u |= uint64(c&0x7F) << shift - if c&0x80 == 0 { - break - } - } - - v := int64(u>>1) ^ (int64(u) << 63 >> 63) - if int64(int(v)) != v { - r.error(errCorruptObject) // TODO - return 0 - } - return int(v) -} - -// readString reads a length-delimited string from the input file. -func (r *objReader) readString() string { - n := r.readInt() - buf := make([]byte, n) - r.readFull(buf) - return string(buf) -} - -// readSymID reads a SymID from the input file. -func (r *objReader) readSymID() SymID { - name, vers := r.readString(), r.readInt() - - // In a symbol name in an object file, "". denotes the - // prefix for the package in which the object file has been found. - // Expand it. - name = strings.Replace(name, `"".`, r.pkgprefix, -1) - - // An individual object file only records version 0 (extern) or 1 (static). - // To make static symbols unique across all files being read, we - // replace version 1 with the version corresponding to the current - // file number. The number is incremented on each call to parseObject. - if vers != 0 { - vers = r.p.MaxVersion - } - - return SymID{name, vers} -} - -// readData reads a data reference from the input file. -func (r *objReader) readData() Data { - n := r.readInt() - d := Data{Offset: r.offset, Size: int64(n)} - r.skip(int64(n)) - return d -} - -// skip skips n bytes in the input. -func (r *objReader) skip(n int64) { - if n < 0 { - r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip")) - } - if n < int64(len(r.tmp)) { - // Since the data is so small, a just reading from the buffered - // reader is better than flushing the buffer and seeking. - r.readFull(r.tmp[:n]) - } else if n <= int64(r.b.Buffered()) { - // Even though the data is not small, it has already been read. - // Advance the buffer instead of seeking. - for n > int64(len(r.tmp)) { - r.readFull(r.tmp[:]) - n -= int64(len(r.tmp)) - } - r.readFull(r.tmp[:n]) - } else { - // Seek, giving up buffered data. - _, err := r.f.Seek(r.offset+n, 0) - if err != nil { - r.error(err) - } - r.offset += n - r.b.Reset(r.f) - } -} - -// Parse parses an object file or archive from r, -// assuming that its import path is pkgpath. -func Parse(r io.ReadSeeker, pkgpath string) (*Package, error) { - if pkgpath == "" { - pkgpath = `""` - } - p := new(Package) - p.ImportPath = pkgpath - - var rd objReader - rd.init(r, p) - err := rd.readFull(rd.tmp[:8]) - if err != nil { - if err == io.EOF { - err = io.ErrUnexpectedEOF - } - return nil, err - } - - switch { - default: - return nil, errNotObject - - case bytes.Equal(rd.tmp[:8], archiveHeader): - if err := rd.parseArchive(); err != nil { - return nil, err - } - case bytes.Equal(rd.tmp[:8], goobjHeader): - if err := rd.parseObject(goobjHeader); err != nil { - return nil, err - } - } - - return p, nil -} - -// trimSpace removes trailing spaces from b and returns the corresponding string. -// This effectively parses the form used in archive headers. -func trimSpace(b []byte) string { - return string(bytes.TrimRight(b, " ")) -} - -// parseArchive parses a Unix archive of Go object files. -// TODO(rsc): Need to skip non-Go object files. -// TODO(rsc): Maybe record table of contents in r.p so that -// linker can avoid having code to parse archives too. -func (r *objReader) parseArchive() error { - for r.offset < r.limit { - if err := r.readFull(r.tmp[:60]); err != nil { - return err - } - data := r.tmp[:60] - - // Each file is preceded by this text header (slice indices in first column): - // 0:16 name - // 16:28 date - // 28:34 uid - // 34:40 gid - // 40:48 mode - // 48:58 size - // 58:60 magic - `\n - // We only care about name, size, and magic. - // The fields are space-padded on the right. - // The size is in decimal. - // The file data - size bytes - follows the header. - // Headers are 2-byte aligned, so if size is odd, an extra padding - // byte sits between the file data and the next header. - // The file data that follows is padded to an even number of bytes: - // if size is odd, an extra padding byte is inserted betw the next header. - if len(data) < 60 { - return errTruncatedArchive - } - if !bytes.Equal(data[58:60], archiveMagic) { - return errCorruptArchive - } - name := trimSpace(data[0:16]) - size, err := strconv.ParseInt(trimSpace(data[48:58]), 10, 64) - if err != nil { - return errCorruptArchive - } - data = data[60:] - fsize := size + size&1 - if fsize < 0 || fsize < size { - return errCorruptArchive - } - switch name { - case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF": - r.skip(size) - default: - oldLimit := r.limit - r.limit = r.offset + size - if err := r.parseObject(nil); err != nil { - return fmt.Errorf("parsing archive member %q: %v", name, err) - } - r.skip(r.limit - r.offset) - r.limit = oldLimit - } - if size&1 != 0 { - r.skip(1) - } - } - return nil -} - -// parseObject parses a single Go object file. -// The prefix is the bytes already read from the file, -// typically in order to detect that this is an object file. -// The object file consists of a textual header ending in "\n!\n" -// and then the part we want to parse begins. -// The format of that part is defined in a comment at the top -// of src/liblink/objfile.c. -func (r *objReader) parseObject(prefix []byte) error { - // TODO(rsc): Maybe use prefix and the initial input to - // record the header line from the file, which would - // give the architecture and other version information. - - r.p.MaxVersion++ - var c1, c2, c3 byte - for { - c1, c2, c3 = c2, c3, r.readByte() - if c3 == 0 { // NUL or EOF, either is bad - return errCorruptObject - } - if c1 == '\n' && c2 == '!' && c3 == '\n' { - break - } - } - - r.readFull(r.tmp[:8]) - if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) { - return r.error(errCorruptObject) - } - - // Direct package dependencies. - for { - s := r.readString() - if s == "" { - break - } - r.p.Imports = append(r.p.Imports, s) - } - - // Symbols. - for { - if b := r.readByte(); b != 0xfe { - if b != 0xff { - return r.error(errCorruptObject) - } - break - } - - typ := r.readInt() - s := &Sym{SymID: r.readSymID()} - r.p.Syms = append(r.p.Syms, s) - s.Kind = SymKind(typ) - s.DupOK = r.readInt() != 0 - s.Size = r.readInt() - s.Type = r.readSymID() - s.Data = r.readData() - s.Reloc = make([]Reloc, r.readInt()) - for i := range s.Reloc { - rel := &s.Reloc[i] - rel.Offset = r.readInt() - rel.Size = r.readInt() - rel.Type = r.readInt() - rel.Add = r.readInt() - r.readInt() // Xadd - ignored - rel.Sym = r.readSymID() - r.readSymID() // Xsym - ignored - } - - if s.Kind == STEXT { - f := new(Func) - s.Func = f - f.Args = r.readInt() - f.Frame = r.readInt() - f.Var = make([]Var, r.readInt()) - for i := range f.Var { - v := &f.Var[i] - v.Name = r.readSymID().Name - v.Offset = r.readInt() - v.Kind = r.readInt() - v.Type = r.readSymID() - } - - f.PCSP = r.readData() - f.PCFile = r.readData() - f.PCLine = r.readData() - f.PCData = make([]Data, r.readInt()) - for i := range f.PCData { - f.PCData[i] = r.readData() - } - f.FuncData = make([]FuncData, r.readInt()) - for i := range f.FuncData { - f.FuncData[i].Sym = r.readSymID() - } - for i := range f.FuncData { - f.FuncData[i].Offset = int64(r.readInt()) // TODO - } - f.File = make([]string, r.readInt()) - for i := range f.File { - f.File[i] = r.readSymID().Name - } - } - } - - r.readFull(r.tmp[:7]) - if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) { - return r.error(errCorruptObject) - } - - return nil -} diff --git a/libgo/go/debug/goobj/read_test.go b/libgo/go/debug/goobj/read_test.go deleted file mode 100644 index dee140533c9..00000000000 --- a/libgo/go/debug/goobj/read_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 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. - -package goobj - -import "testing" - -var importPathToPrefixTests = []struct { - in string - out string -}{ - {"runtime", "runtime"}, - {"sync/atomic", "sync/atomic"}, - {"code.google.com/p/go.tools/godoc", "code.google.com/p/go.tools/godoc"}, - {"foo.bar/baz.quux", "foo.bar/baz%2equux"}, - {"", ""}, - {"%foo%bar", "%25foo%25bar"}, - {"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"}, -} - -func TestImportPathToPrefix(t *testing.T) { - for _, tt := range importPathToPrefixTests { - if out := importPathToPrefix(tt.in); out != tt.out { - t.Errorf("importPathToPrefix(%q) = %q, want %q", tt.in, out, tt.out) - } - } -} diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go index ed9b2a69120..da13c510064 100644 --- a/libgo/go/debug/macho/file.go +++ b/libgo/go/debug/macho/file.go @@ -11,7 +11,6 @@ import ( "bytes" "debug/dwarf" "encoding/binary" - "errors" "fmt" "io" "os" @@ -481,7 +480,7 @@ func (f *File) DWARF() (*dwarf.Data, error) { name = "__debug_" + name s := f.Section(name) if s == nil { - return nil, errors.New("missing Mach-O section " + name) + continue } b, err := s.Data() if err != nil && uint64(len(b)) < s.Size { diff --git a/libgo/go/debug/macho/file_test.go b/libgo/go/debug/macho/file_test.go index 0de9184c227..4797780ce77 100644 --- a/libgo/go/debug/macho/file_test.go +++ b/libgo/go/debug/macho/file_test.go @@ -184,7 +184,7 @@ func TestOpenFat(t *testing.T) { ftArch := &fileTests[i] if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu { - t.Error("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu) + t.Errorf("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu) } if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) { @@ -202,9 +202,9 @@ func TestOpenFatFailure(t *testing.T) { filename = "testdata/gcc-386-darwin-exec" // not a fat Mach-O ff, err := OpenFat(filename) if err != ErrNotFat { - t.Errorf("OpenFat %s: got %v, want ErrNotFat", err) + t.Errorf("OpenFat %s: got %v, want ErrNotFat", filename, err) } if ff != nil { - t.Errorf("OpenFat %s: got %v, want nil", ff) + t.Errorf("OpenFat %s: got %v, want nil", filename, ff) } } diff --git a/libgo/go/debug/macho/macho.go b/libgo/go/debug/macho/macho.go index 09f4d0ec91c..d9678c8eda4 100644 --- a/libgo/go/debug/macho/macho.go +++ b/libgo/go/debug/macho/macho.go @@ -44,14 +44,22 @@ const ( // A Cpu is a Mach-O cpu type. type Cpu uint32 +const cpuArch64 = 0x01000000 + const ( Cpu386 Cpu = 7 - CpuAmd64 Cpu = Cpu386 + 1<<24 + CpuAmd64 Cpu = Cpu386 | cpuArch64 + CpuArm Cpu = 12 + CpuPpc Cpu = 18 + CpuPpc64 Cpu = CpuPpc | cpuArch64 ) var cpuStrings = []intName{ {uint32(Cpu386), "Cpu386"}, {uint32(CpuAmd64), "CpuAmd64"}, + {uint32(CpuArm), "CpuArm"}, + {uint32(CpuPpc), "CpuPpc"}, + {uint32(CpuPpc64), "CpuPpc64"}, } func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) } diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go index d0005bacf38..ce6f1408fe9 100644 --- a/libgo/go/debug/pe/file.go +++ b/libgo/go/debug/pe/file.go @@ -13,13 +13,15 @@ import ( "io" "os" "strconv" + "unsafe" ) // A File represents an open PE file. type File struct { FileHeader - Sections []*Section - Symbols []*Symbol + OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64 + Sections []*Section + Symbols []*Symbol closer io.Closer } @@ -196,10 +198,33 @@ func NewFile(r io.ReaderAt) (*File, error) { } } - // Process sections. + // Read optional header. sr.Seek(base, os.SEEK_SET) - binary.Read(sr, binary.LittleEndian, &f.FileHeader) - sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader + if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil { + return nil, err + } + var oh32 OptionalHeader32 + var oh64 OptionalHeader64 + switch uintptr(f.FileHeader.SizeOfOptionalHeader) { + case unsafe.Sizeof(oh32): + if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil { + return nil, err + } + if oh32.Magic != 0x10b { // PE32 + return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic) + } + f.OptionalHeader = &oh32 + case unsafe.Sizeof(oh64): + if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil { + return nil, err + } + if oh64.Magic != 0x20b { // PE32+ + return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic) + } + f.OptionalHeader = &oh64 + } + + // Process sections. f.Sections = make([]*Section, f.FileHeader.NumberOfSections) for i := 0; i < int(f.FileHeader.NumberOfSections); i++ { sh := new(SectionHeader32) diff --git a/libgo/go/debug/pe/file_test.go b/libgo/go/debug/pe/file_test.go index c0f9fcb95db..ddbb2717441 100644 --- a/libgo/go/debug/pe/file_test.go +++ b/libgo/go/debug/pe/file_test.go @@ -12,6 +12,7 @@ import ( type fileTest struct { file string hdr FileHeader + opthdr interface{} sections []*SectionHeader symbols []*Symbol } @@ -20,6 +21,7 @@ var fileTests = []fileTest{ { "testdata/gcc-386-mingw-obj", FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104}, + nil, []*SectionHeader{ {".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020}, {".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264}, @@ -56,27 +58,130 @@ var fileTests = []fileTest{ { "testdata/gcc-386-mingw-exec", FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107}, + &OptionalHeader32{ + 0x10b, 0x2, 0x38, 0xe00, 0x1a00, 0x200, 0x1160, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x10000, 0x400, 0x14abb, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10, + [16]DataDirectory{ + {0x0, 0x0}, + {0x5000, 0x3c8}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x7000, 0x18}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + }, + }, + []*SectionHeader{ + {".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, + {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080}, + {".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000}, + {".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + }, + []*Symbol{}, + }, + { + "testdata/gcc-amd64-mingw-obj", + FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4}, + nil, + []*SectionHeader{ + {".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020}, + {".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, + {".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080}, + {".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040}, + {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040}, + }, + []*Symbol{ + {".file", 0x0, -2, 0x0, 0x67}, + {"main", 0x0, 1, 0x20, 0x2}, + {".text", 0x0, 1, 0x0, 0x3}, + {".data", 0x0, 2, 0x0, 0x3}, + {".bss", 0x0, 3, 0x0, 0x3}, + {".rdata", 0x0, 4, 0x0, 0x3}, + {".xdata", 0x0, 5, 0x0, 0x3}, + {".pdata", 0x0, 6, 0x0, 0x3}, + {"__main", 0x0, 0, 0x20, 0x2}, + {"puts", 0x0, 0, 0x20, 0x2}, + }, + }, + { + "testdata/gcc-amd64-mingw-exec", + FileHeader{0x8664, 0x9, 0x53472993, 0x0, 0x0, 0xf0, 0x22f}, + &OptionalHeader64{ + 0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x11000, 0x400, 0x1841e, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10, + [16]DataDirectory{ + {0x0, 0x0}, + {0xe000, 0x990}, + {0x0, 0x0}, + {0xa000, 0x498}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x10000, 0x28}, + {0x0, 0x0}, + {0x0, 0x0}, + {0xe254, 0x218}, + {0x0, 0x0}, + {0x0, 0x0}, + {0x0, 0x0}, + }, + }, []*SectionHeader{ - {Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060}, - {Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040}, - {Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040}, - {Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080}, - {Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040}, - {Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040}, - {Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040}, - {Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000}, - {Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000}, - {Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000}, - {Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000}, - {Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000}, - {Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000}, - {Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000}, - {Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000}, + {".text", 0x6860, 0x1000, 0x6a00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500020}, + {".data", 0xe0, 0x8000, 0x200, 0x6e00, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, + {".rdata", 0x6b0, 0x9000, 0x800, 0x7000, 0x0, 0x0, 0x0, 0x0, 0x40600040}, + {".pdata", 0x498, 0xa000, 0x600, 0x7800, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".xdata", 0x488, 0xb000, 0x600, 0x7e00, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080}, + {".idata", 0x990, 0xe000, 0xa00, 0x8400, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".CRT", 0x68, 0xf000, 0x200, 0x8e00, 0x0, 0x0, 0x0, 0x0, 0xc0400040}, + {".tls", 0x48, 0x10000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0600040}, }, []*Symbol{}, }, } +func isOptHdrEq(a, b interface{}) bool { + switch va := a.(type) { + case *OptionalHeader32: + vb, ok := b.(*OptionalHeader32) + if !ok { + return false + } + return *vb == *va + case *OptionalHeader64: + vb, ok := b.(*OptionalHeader64) + if !ok { + return false + } + return *vb == *va + case nil: + return b == nil + } + return false +} + func TestOpen(t *testing.T) { for i := range fileTests { tt := &fileTests[i] @@ -90,6 +195,10 @@ func TestOpen(t *testing.T) { t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) continue } + if !isOptHdrEq(tt.opthdr, f.OptionalHeader) { + t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr) + continue + } for i, sh := range f.Sections { if i >= len(tt.sections) { diff --git a/libgo/go/debug/pe/pe.go b/libgo/go/debug/pe/pe.go index 0606217b3bf..8e90b1b513a 100644 --- a/libgo/go/debug/pe/pe.go +++ b/libgo/go/debug/pe/pe.go @@ -14,6 +14,78 @@ type FileHeader struct { Characteristics uint16 } +type DataDirectory struct { + VirtualAddress uint32 + Size uint32 +} + +type OptionalHeader32 struct { + Magic uint16 + MajorLinkerVersion uint8 + MinorLinkerVersion uint8 + SizeOfCode uint32 + SizeOfInitializedData uint32 + SizeOfUninitializedData uint32 + AddressOfEntryPoint uint32 + BaseOfCode uint32 + BaseOfData uint32 + ImageBase uint32 + SectionAlignment uint32 + FileAlignment uint32 + MajorOperatingSystemVersion uint16 + MinorOperatingSystemVersion uint16 + MajorImageVersion uint16 + MinorImageVersion uint16 + MajorSubsystemVersion uint16 + MinorSubsystemVersion uint16 + Win32VersionValue uint32 + SizeOfImage uint32 + SizeOfHeaders uint32 + CheckSum uint32 + Subsystem uint16 + DllCharacteristics uint16 + SizeOfStackReserve uint32 + SizeOfStackCommit uint32 + SizeOfHeapReserve uint32 + SizeOfHeapCommit uint32 + LoaderFlags uint32 + NumberOfRvaAndSizes uint32 + DataDirectory [16]DataDirectory +} + +type OptionalHeader64 struct { + Magic uint16 + MajorLinkerVersion uint8 + MinorLinkerVersion uint8 + SizeOfCode uint32 + SizeOfInitializedData uint32 + SizeOfUninitializedData uint32 + AddressOfEntryPoint uint32 + BaseOfCode uint32 + ImageBase uint64 + SectionAlignment uint32 + FileAlignment uint32 + MajorOperatingSystemVersion uint16 + MinorOperatingSystemVersion uint16 + MajorImageVersion uint16 + MinorImageVersion uint16 + MajorSubsystemVersion uint16 + MinorSubsystemVersion uint16 + Win32VersionValue uint32 + SizeOfImage uint32 + SizeOfHeaders uint32 + CheckSum uint32 + Subsystem uint16 + DllCharacteristics uint16 + SizeOfStackReserve uint64 + SizeOfStackCommit uint64 + SizeOfHeapReserve uint64 + SizeOfHeapCommit uint64 + LoaderFlags uint32 + NumberOfRvaAndSizes uint32 + DataDirectory [16]DataDirectory +} + type SectionHeader32 struct { Name [8]uint8 VirtualSize uint32 diff --git a/libgo/go/debug/pe/testdata/gcc-amd64-mingw-exec b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-exec Binary files differnew file mode 100644 index 00000000000..78d4e5fed98 --- /dev/null +++ b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-exec diff --git a/libgo/go/debug/pe/testdata/gcc-amd64-mingw-obj b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-obj Binary files differnew file mode 100644 index 00000000000..48ae7921f33 --- /dev/null +++ b/libgo/go/debug/pe/testdata/gcc-amd64-mingw-obj diff --git a/libgo/go/debug/plan9obj/file.go b/libgo/go/debug/plan9obj/file.go index a4c95a92a5c..60a5857193e 100644 --- a/libgo/go/debug/plan9obj/file.go +++ b/libgo/go/debug/plan9obj/file.go @@ -13,9 +13,12 @@ import ( "os" ) -// A FileHeader represents an Plan 9 a.out file header. +// A FileHeader represents a Plan 9 a.out file header. type FileHeader struct { - Ptrsz int + Magic uint32 + Bss uint32 + Entry uint64 + PtrSize int } // A File represents an open Plan 9 a.out file. @@ -25,13 +28,16 @@ type File struct { closer io.Closer } +// A SectionHeader represents a single Plan 9 a.out section header. +// This structure doesn't exist on-disk, but eases navigation +// through the object file. type SectionHeader struct { Name string Size uint32 Offset uint32 } -// A Section represents a single section in an Plan 9 a.out file. +// A Section represents a single section in a Plan 9 a.out file. type Section struct { SectionHeader @@ -49,41 +55,15 @@ type Section struct { func (s *Section) Data() ([]byte, error) { dat := make([]byte, s.sr.Size()) n, err := s.sr.ReadAt(dat, 0) + if n == len(dat) { + err = nil + } return dat[0:n], err } // Open returns a new ReadSeeker reading the Plan 9 a.out section. func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } -// A ProgHeader represents a single Plan 9 a.out program header. -type ProgHeader struct { - Magic uint32 - Text uint32 - Data uint32 - Bss uint32 - Syms uint32 - Entry uint64 - Spsz uint32 - Pcsz uint32 -} - -// A Prog represents the program header in an Plan 9 a.out binary. -type Prog struct { - ProgHeader - - // Embed ReaderAt for ReadAt method. - // Do not embed SectionReader directly - // to avoid having Read and Seek. - // If a client wants Read and Seek it must use - // Open() to avoid fighting over the seek offset - // with other clients. - io.ReaderAt - sr *io.SectionReader -} - -// Open returns a new ReadSeeker reading the Plan 9 a.out program body. -func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } - // A Symbol represents an entry in a Plan 9 a.out symbol table section. type Sym struct { Value uint64 @@ -95,13 +75,15 @@ type Sym struct { * Plan 9 a.out reader */ -type FormatError struct { +// formatError is returned by some operations if the data does +// not have the correct format for an object file. +type formatError struct { off int msg string val interface{} } -func (e *FormatError) Error() string { +func (e *formatError) Error() string { msg := e.msg if e.val != nil { msg += fmt.Sprintf(" '%v'", e.val) @@ -110,7 +92,7 @@ func (e *FormatError) Error() string { return msg } -// Open opens the named file using os.Open and prepares it for use as an Plan 9 a.out binary. +// Open opens the named file using os.Open and prepares it for use as a Plan 9 a.out binary. func Open(name string) (*File, error) { f, err := os.Open(name) if err != nil { @@ -137,16 +119,16 @@ func (f *File) Close() error { return err } -func parseMagic(magic [4]byte) (*ExecTable, error) { - for _, e := range exectab { - if string(magic[:]) == e.Magic { - return &e, nil - } +func parseMagic(magic []byte) (uint32, error) { + m := binary.BigEndian.Uint32(magic) + switch m { + case Magic386, MagicAMD64, MagicARM: + return m, nil } - return nil, &FormatError{0, "bad magic number", magic[:]} + return 0, &formatError{0, "bad magic number", magic} } -// NewFile creates a new File for accessing an Plan 9 binary in an underlying reader. +// NewFile creates a new File for accessing a Plan 9 binary in an underlying reader. // The Plan 9 binary is expected to start at position 0 in the ReaderAt. func NewFile(r io.ReaderAt) (*File, error) { sr := io.NewSectionReader(r, 0, 1<<63-1) @@ -155,34 +137,31 @@ func NewFile(r io.ReaderAt) (*File, error) { if _, err := r.ReadAt(magic[:], 0); err != nil { return nil, err } - mp, err := parseMagic(magic) + _, err := parseMagic(magic[:]) if err != nil { return nil, err } - f := &File{FileHeader{mp.Ptrsz}, nil, nil} - ph := new(prog) if err := binary.Read(sr, binary.BigEndian, ph); err != nil { return nil, err } - p := new(Prog) - p.ProgHeader = ProgHeader{ - Magic: ph.Magic, - Text: ph.Text, - Data: ph.Data, - Bss: ph.Bss, - Syms: ph.Syms, - Entry: uint64(ph.Entry), - Spsz: ph.Spsz, - Pcsz: ph.Pcsz, - } + f := &File{FileHeader: FileHeader{ + Magic: ph.Magic, + Bss: ph.Bss, + Entry: uint64(ph.Entry), + PtrSize: 4, + }} + + hdrSize := 4 * 8 - if mp.Ptrsz == 8 { - if err := binary.Read(sr, binary.BigEndian, &p.Entry); err != nil { + if ph.Magic&Magic64 != 0 { + if err := binary.Read(sr, binary.BigEndian, &f.Entry); err != nil { return nil, err } + f.PtrSize = 8 + hdrSize += 8 } var sects = []struct { @@ -198,7 +177,7 @@ func NewFile(r io.ReaderAt) (*File, error) { f.Sections = make([]*Section, 5) - off := mp.Hsize + off := uint32(hdrSize) for i, sect := range sects { s := new(Section) @@ -208,7 +187,7 @@ func NewFile(r io.ReaderAt) (*File, error) { Offset: off, } off += sect.size - s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size)) + s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size)) s.ReaderAt = s.sr f.Sections[i] = s } @@ -223,7 +202,7 @@ func walksymtab(data []byte, ptrsz int, fn func(sym) error) error { for len(p) >= 4 { // Symbol type, value. if len(p) < ptrsz { - return &FormatError{len(data), "unexpected EOF", nil} + return &formatError{len(data), "unexpected EOF", nil} } // fixed-width value if ptrsz == 8 { @@ -259,7 +238,7 @@ func walksymtab(data []byte, ptrsz int, fn func(sym) error) error { } } if len(p) < i+nnul { - return &FormatError{len(data), "unexpected EOF", nil} + return &formatError{len(data), "unexpected EOF", nil} } s.name = p[0:i] i += nnul @@ -298,7 +277,7 @@ func newTable(symtab []byte, ptrsz int) ([]Sym, error) { eltIdx := binary.BigEndian.Uint16(s.name[i : i+2]) elt, ok := fname[eltIdx] if !ok { - return &FormatError{-1, "bad filename code", eltIdx} + return &formatError{-1, "bad filename code", eltIdx} } if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' { ts.Name += "/" @@ -331,7 +310,7 @@ func (f *File) Symbols() ([]Sym, error) { return nil, errors.New("cannot load symbol section") } - return newTable(symtab, f.Ptrsz) + return newTable(symtab, f.PtrSize) } // Section returns a section with the given name, or nil if no such diff --git a/libgo/go/debug/plan9obj/file_test.go b/libgo/go/debug/plan9obj/file_test.go index cc1db409295..96186d81565 100644 --- a/libgo/go/debug/plan9obj/file_test.go +++ b/libgo/go/debug/plan9obj/file_test.go @@ -18,7 +18,7 @@ type fileTest struct { var fileTests = []fileTest{ { "testdata/386-plan9-exec", - FileHeader{4}, + FileHeader{Magic386, 0x324, 0x14, 4}, []*SectionHeader{ {"text", 0x4c5f, 0x20}, {"data", 0x94c, 0x4c7f}, @@ -29,7 +29,7 @@ var fileTests = []fileTest{ }, { "testdata/amd64-plan9-exec", - FileHeader{8}, + FileHeader{MagicAMD64, 0x618, 0x13, 8}, []*SectionHeader{ {"text", 0x4213, 0x28}, {"data", 0xa80, 0x423b}, diff --git a/libgo/go/debug/plan9obj/plan9obj.go b/libgo/go/debug/plan9obj/plan9obj.go index 4e3b08f4164..af9858562f9 100644 --- a/libgo/go/debug/plan9obj/plan9obj.go +++ b/libgo/go/debug/plan9obj/plan9obj.go @@ -8,11 +8,6 @@ package plan9obj -import ( - "bytes" - "encoding/binary" -) - // Plan 9 Program header. type prog struct { Magic uint32 /* magic number */ @@ -33,59 +28,9 @@ type sym struct { } const ( - hsize = 4 * 8 - _HDR_MAGIC = 0x00008000 /* header expansion */ -) - -func magic(f, b int) string { - buf := new(bytes.Buffer) - var i uint32 = uint32((f) | ((((4 * (b)) + 0) * (b)) + 7)) - binary.Write(buf, binary.BigEndian, i) - return string(buf.Bytes()) -} + Magic64 = 0x8000 // 64-bit expanded header -var ( - _A_MAGIC = magic(0, 8) /* 68020 (retired) */ - _I_MAGIC = magic(0, 11) /* intel 386 */ - _J_MAGIC = magic(0, 12) /* intel 960 (retired) */ - _K_MAGIC = magic(0, 13) /* sparc */ - _V_MAGIC = magic(0, 16) /* mips 3000 BE */ - _X_MAGIC = magic(0, 17) /* att dsp 3210 (retired) */ - _M_MAGIC = magic(0, 18) /* mips 4000 BE */ - _D_MAGIC = magic(0, 19) /* amd 29000 (retired) */ - _E_MAGIC = magic(0, 20) /* arm */ - _Q_MAGIC = magic(0, 21) /* powerpc */ - _N_MAGIC = magic(0, 22) /* mips 4000 LE */ - _L_MAGIC = magic(0, 23) /* dec alpha (retired) */ - _P_MAGIC = magic(0, 24) /* mips 3000 LE */ - _U_MAGIC = magic(0, 25) /* sparc64 (retired) */ - _S_MAGIC = magic(_HDR_MAGIC, 26) /* amd64 */ - _T_MAGIC = magic(_HDR_MAGIC, 27) /* powerpc64 */ - _R_MAGIC = magic(_HDR_MAGIC, 28) /* arm64 */ + Magic386 = (4*11+0)*11 + 7 + MagicAMD64 = (4*26+0)*26 + 7 + Magic64 + MagicARM = (4*20+0)*20 + 7 ) - -type ExecTable struct { - Magic string - Ptrsz int - Hsize uint32 -} - -var exectab = []ExecTable{ - {_A_MAGIC, 4, hsize}, - {_I_MAGIC, 4, hsize}, - {_J_MAGIC, 4, hsize}, - {_K_MAGIC, 4, hsize}, - {_V_MAGIC, 4, hsize}, - {_X_MAGIC, 4, hsize}, - {_M_MAGIC, 4, hsize}, - {_D_MAGIC, 4, hsize}, - {_E_MAGIC, 4, hsize}, - {_Q_MAGIC, 4, hsize}, - {_N_MAGIC, 4, hsize}, - {_L_MAGIC, 4, hsize}, - {_P_MAGIC, 4, hsize}, - {_U_MAGIC, 4, hsize}, - {_S_MAGIC, 8, hsize + 8}, - {_T_MAGIC, 8, hsize + 8}, - {_R_MAGIC, 8, hsize + 8}, -} diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go index e2afc587140..60da304b55e 100644 --- a/libgo/go/encoding/ascii85/ascii85.go +++ b/libgo/go/encoding/ascii85/ascii85.go @@ -281,6 +281,18 @@ func (d *decoder) Read(p []byte) (n int, err error) { d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf]) continue // copy out and return } + if ndst == 0 && d.err == nil { + // Special case: input buffer is mostly filled with non-data bytes. + // Filter out such bytes to make room for more input. + off := 0 + for i := 0; i < d.nbuf; i++ { + if d.buf[i] > ' ' { + d.buf[off] = d.buf[i] + off++ + } + } + d.nbuf = off + } } // Out of input, out of decoded output. Check errors. diff --git a/libgo/go/encoding/ascii85/ascii85_test.go b/libgo/go/encoding/ascii85/ascii85_test.go index 77bc465d594..aad199b4fad 100644 --- a/libgo/go/encoding/ascii85/ascii85_test.go +++ b/libgo/go/encoding/ascii85/ascii85_test.go @@ -197,3 +197,14 @@ func TestBig(t *testing.T) { t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i) } } + +func TestDecoderInternalWhitespace(t *testing.T) { + s := strings.Repeat(" ", 2048) + "z" + decoded, err := ioutil.ReadAll(NewDecoder(strings.NewReader(s))) + if err != nil { + t.Errorf("Decode gave error %v", err) + } + if want := []byte("\000\000\000\000"); !bytes.Equal(want, decoded) { + t.Errorf("Decode failed: got %v, want %v", decoded, want) + } +} diff --git a/libgo/go/encoding/asn1/asn1.go b/libgo/go/encoding/asn1/asn1.go index 7a3c3797c8b..ec7f91c1bba 100644 --- a/libgo/go/encoding/asn1/asn1.go +++ b/libgo/go/encoding/asn1/asn1.go @@ -465,11 +465,15 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type if err != nil { return } - // We pretend that various other string types are PRINTABLE STRINGs - // so that a sequence of them can be parsed into a []string. switch t.tag { case tagIA5String, tagGeneralString, tagT61String, tagUTF8String: + // We pretend that various other string types are + // PRINTABLE STRINGs so that a sequence of them can be + // parsed into a []string. t.tag = tagPrintableString + case tagGeneralizedTime, tagUTCTime: + // Likewise, both time types are treated the same. + t.tag = tagUTCTime } if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag { diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go index da50cf25e83..e26fe59b305 100644 --- a/libgo/go/encoding/asn1/marshal.go +++ b/libgo/go/encoding/asn1/marshal.go @@ -295,8 +295,23 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) { return out.WriteByte(byte('0' + v%10)) } +func marshalFourDigits(out *forkableWriter, v int) (err error) { + var bytes [4]byte + for i := range bytes { + bytes[3-i] = '0' + byte(v%10) + v /= 10 + } + _, err = out.Write(bytes[:]) + return +} + +func outsideUTCRange(t time.Time) bool { + year := t.Year() + return year < 1950 || year >= 2050 +} + func marshalUTCTime(out *forkableWriter, t time.Time) (err error) { - year, month, day := t.Date() + year := t.Year() switch { case 1950 <= year && year < 2000: @@ -310,6 +325,24 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) { return } + return marshalTimeCommon(out, t) +} + +func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) { + year := t.Year() + if year < 0 || year > 9999 { + return StructuralError{"cannot represent time as GeneralizedTime"} + } + if err = marshalFourDigits(out, year); err != nil { + return + } + + return marshalTimeCommon(out, t) +} + +func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) { + _, month, day := t.Date() + err = marshalTwoDigits(out, int(month)) if err != nil { return @@ -378,7 +411,12 @@ func stripTagAndLength(in []byte) []byte { func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) { switch value.Type() { case timeType: - return marshalUTCTime(out, value.Interface().(time.Time)) + t := value.Interface().(time.Time) + if outsideUTCRange(t) { + return marshalGeneralizedTime(out, t) + } else { + return marshalUTCTime(out, t) + } case bitStringType: return marshalBitString(out, value.Interface().(BitString)) case objectIdentifierType: @@ -504,7 +542,8 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) return StructuralError{"explicit string type given to non-string member"} } - if tag == tagPrintableString { + switch tag { + case tagPrintableString: if params.stringType == 0 { // This is a string without an explicit string type. We'll use // a PrintableString if the character set in the string is @@ -521,6 +560,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) } else { tag = params.stringType } + case tagUTCTime: + if outsideUTCRange(v.Interface().(time.Time)) { + tag = tagGeneralizedTime + } } if params.set { diff --git a/libgo/go/encoding/asn1/marshal_test.go b/libgo/go/encoding/asn1/marshal_test.go index 763c86da23f..a15acbed012 100644 --- a/libgo/go/encoding/asn1/marshal_test.go +++ b/libgo/go/encoding/asn1/marshal_test.go @@ -67,6 +67,14 @@ type marshalTest struct { out string // hex encoded } +func farFuture() time.Time { + t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z") + if err != nil { + panic(err) + } + return t +} + var marshalTests = []marshalTest{ {10, "02010a"}, {127, "02017f"}, @@ -83,6 +91,7 @@ var marshalTests = []marshalTest{ {time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"}, {time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"}, {time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"}, + {farFuture(), "180f32313030303430353132303130315a"}, {BitString{[]byte{0x80}, 1}, "03020780"}, {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"}, {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"}, diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go index fe17b732207..d770de3915f 100644 --- a/libgo/go/encoding/base32/base32.go +++ b/libgo/go/encoding/base32/base32.go @@ -179,13 +179,11 @@ func (e *encoder) Write(p []byte) (n int, err error) { nn := len(e.out) / 8 * 5 if nn > len(p) { nn = len(p) + nn -= nn % 5 } - nn -= nn % 5 - if nn > 0 { - e.enc.Encode(e.out[0:], p[0:nn]) - if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil { - return n, e.err - } + e.enc.Encode(e.out[0:], p[0:nn]) + if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil { + return n, e.err } n += nn p = p[nn:] @@ -268,7 +266,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { // 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not // valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing // the five valid padding lengths, and Section 9 "Illustrations and - // Examples" for an illustration for how the the 1st, 3rd and 6th base32 + // Examples" for an illustration for how the 1st, 3rd and 6th base32 // src bytes do not yield enough information to decode a dst byte. if dlen == 1 || dlen == 3 || dlen == 6 { return n, false, CorruptInputError(olen - len(src) - 1) diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go index 85e398fd0b7..e38c26d0ec7 100644 --- a/libgo/go/encoding/base64/base64.go +++ b/libgo/go/encoding/base64/base64.go @@ -159,13 +159,11 @@ func (e *encoder) Write(p []byte) (n int, err error) { nn := len(e.out) / 4 * 3 if nn > len(p) { nn = len(p) + nn -= nn % 3 } - nn -= nn % 3 - if nn > 0 { - e.enc.Encode(e.out[0:], p[0:nn]) - if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil { - return n, e.err - } + e.enc.Encode(e.out[0:], p[0:nn]) + if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil { + return n, e.err } n += nn p = p[nn:] @@ -226,21 +224,33 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { var dbuf [4]byte dlen := 4 - for j := 0; j < 4; { + for j := range dbuf { if len(src) == 0 { return n, false, CorruptInputError(olen - len(src) - j) } in := src[0] src = src[1:] - if in == '=' && j >= 2 && len(src) < 4 { + if in == '=' { // We've reached the end and there's padding - if len(src)+j < 4-1 { - // not enough padding - return n, false, CorruptInputError(olen) - } - if len(src) > 0 && src[0] != '=' { + switch j { + case 0, 1: // incorrect padding return n, false, CorruptInputError(olen - len(src) - 1) + case 2: + // "==" is expected, the first "=" is already consumed. + if len(src) == 0 { + // not enough padding + return n, false, CorruptInputError(olen) + } + if src[0] != '=' { + // incorrect padding + return n, false, CorruptInputError(olen - len(src) - 1) + } + src = src[1:] + } + if len(src) > 0 { + // trailing garbage + err = CorruptInputError(olen - len(src)) } dlen, end = j, true break @@ -249,7 +259,6 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { if dbuf[j] == 0xFF { return n, false, CorruptInputError(olen - len(src) - 1) } - j++ } // Pack 4x 6-bit source blocks into 3 byte destination @@ -268,7 +277,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { n += dlen - 1 } - return n, end, nil + return n, end, err } // Decode decodes src using the encoding enc. It writes at most diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go index 6bcc724d9b5..a075194e03e 100644 --- a/libgo/go/encoding/base64/base64_test.go +++ b/libgo/go/encoding/base64/base64_test.go @@ -9,6 +9,7 @@ import ( "errors" "io" "io/ioutil" + "reflect" "strings" "testing" "time" @@ -149,9 +150,13 @@ func TestDecodeCorrupt(t *testing.T) { }{ {"", -1}, {"!!!!", 0}, + {"====", 0}, {"x===", 1}, + {"=AAA", 0}, + {"A=AA", 1}, {"AA=A", 2}, - {"AAA=AAAA", 3}, + {"AA==A", 4}, + {"AAA=AAAA", 4}, {"AAAAA", 4}, {"AAAAAA", 4}, {"A=", 1}, @@ -161,6 +166,7 @@ func TestDecodeCorrupt(t *testing.T) { {"AAA=", -1}, {"AAAA", -1}, {"AAAAAA=", 7}, + {"YWJjZA=====", 8}, } for _, tc := range testCases { dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input))) @@ -325,3 +331,14 @@ bqbPb06551Y4 t.Error("Decoded results not equal") } } + +func TestDecoderIssue7733(t *testing.T) { + s, err := StdEncoding.DecodeString("YWJjZA=====") + want := CorruptInputError(8) + if !reflect.DeepEqual(want, err) { + t.Errorf("Error = %v; want CorruptInputError(8)", err) + } + if string(s) != "abcd" { + t.Errorf("DecodeString = %q; want abcd", s) + } +} diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go index f3466b9af03..a5694876ac4 100644 --- a/libgo/go/encoding/binary/binary.go +++ b/libgo/go/encoding/binary/binary.go @@ -133,6 +133,7 @@ func (bigEndian) GoString() string { return "binary.BigEndian" } // When reading into structs, the field data for fields with // blank (_) field names is skipped; i.e., blank field names // may be used for padding. +// When reading into a struct, all non-blank fields must be exported. func Read(r io.Reader, order ByteOrder, data interface{}) error { // Fast path for basic types and slices. if n := intDataSize(data); n != 0 { diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go index 1aa6ecd2486..c80c90383af 100644 --- a/libgo/go/encoding/binary/binary_test.go +++ b/libgo/go/encoding/binary/binary_test.go @@ -265,6 +265,30 @@ func TestBlankFields(t *testing.T) { } } +// An attempt to read into a struct with an unexported field will +// panic. This is probably not the best choice, but at this point +// anything else would be an API change. + +type Unexported struct { + a int32 +} + +func TestUnexportedRead(t *testing.T) { + var buf bytes.Buffer + u1 := Unexported{a: 1} + if err := Write(&buf, LittleEndian, &u1); err != nil { + t.Fatal(err) + } + + defer func() { + if recover() == nil { + t.Fatal("did not panic") + } + }() + var u2 Unexported + Read(&buf, LittleEndian, &u2) +} + type byteSliceReader struct { remain []byte } diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go index aa186a582e8..d8513148ec2 100644 --- a/libgo/go/encoding/gob/decode.go +++ b/libgo/go/encoding/gob/decode.go @@ -685,7 +685,7 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) { // but first it checks that the assignment will succeed. func setInterfaceValue(ivalue reflect.Value, value reflect.Value) { if !value.Type().AssignableTo(ivalue.Type()) { - errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type()) + errorf("%s is not assignable to type %s", value.Type(), ivalue.Type()) } ivalue.Set(value) } diff --git a/libgo/go/encoding/gob/decoder.go b/libgo/go/encoding/gob/decoder.go index 04f706ca540..3a769ec1254 100644 --- a/libgo/go/encoding/gob/decoder.go +++ b/libgo/go/encoding/gob/decoder.go @@ -183,11 +183,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { return -1 } -// Decode reads the next value from the connection and stores +// Decode reads the next value from the input stream and stores // it in the data represented by the empty interface value. // If e is nil, the value will be discarded. Otherwise, // the value underlying e must be a pointer to the // correct type for the next data item received. +// If the input is at EOF, Decode returns io.EOF and +// does not modify e. func (dec *Decoder) Decode(e interface{}) error { if e == nil { return dec.DecodeValue(reflect.Value{}) @@ -202,10 +204,12 @@ func (dec *Decoder) Decode(e interface{}) error { return dec.DecodeValue(value) } -// DecodeValue reads the next value from the connection. +// DecodeValue reads the next value from the input stream. // If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value. // Otherwise, it stores the value into v. In that case, v must represent // a non-nil pointer to data or be an assignable reflect.Value (v.CanSet()) +// If the input is at EOF, DecodeValue returns io.EOF and +// does not modify e. func (dec *Decoder) DecodeValue(v reflect.Value) error { if v.IsValid() { if v.Kind() == reflect.Ptr && !v.IsNil() { diff --git a/libgo/go/encoding/gob/encode.go b/libgo/go/encoding/gob/encode.go index d158b6442a8..7831c02d139 100644 --- a/libgo/go/encoding/gob/encode.go +++ b/libgo/go/encoding/gob/encode.go @@ -491,7 +491,7 @@ func isZero(val reflect.Value) bool { return !val.Bool() case reflect.Complex64, reflect.Complex128: return val.Complex() == 0 - case reflect.Chan, reflect.Func, reflect.Ptr: + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr: return val.IsNil() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return val.Int() == 0 diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go index 0193e2b67d4..157b7723a75 100644 --- a/libgo/go/encoding/gob/gobencdec_test.go +++ b/libgo/go/encoding/gob/gobencdec_test.go @@ -705,13 +705,14 @@ func TestGobEncoderExtraIndirect(t *testing.T) { } // Another bug: this caused a crash with the new Go1 Time type. -// We throw in a gob-encoding array, to test another case of isZero - +// We throw in a gob-encoding array, to test another case of isZero, +// and a struct containing an nil interface, to test a third. type isZeroBug struct { T time.Time S string I int A isZeroBugArray + F isZeroBugInterface } type isZeroBugArray [2]uint8 @@ -731,8 +732,20 @@ func (a *isZeroBugArray) GobDecode(data []byte) error { return nil } +type isZeroBugInterface struct { + I interface{} +} + +func (i isZeroBugInterface) GobEncode() (b []byte, e error) { + return []byte{}, nil +} + +func (i *isZeroBugInterface) GobDecode(data []byte) error { + return nil +} + func TestGobEncodeIsZero(t *testing.T) { - x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}} + x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}} b := new(bytes.Buffer) enc := NewEncoder(b) err := enc.Encode(x) diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go index 167d00e032a..d1fc7024a97 100644 --- a/libgo/go/encoding/hex/hex.go +++ b/libgo/go/encoding/hex/hex.go @@ -146,6 +146,9 @@ func (h *dumper) Write(data []byte) (n int, err error) { h.buf[12] = ' ' h.buf[13] = ' ' _, err = h.w.Write(h.buf[4:]) + if err != nil { + return + } } Encode(h.buf[:], data[i:i+1]) h.buf[2] = ' ' diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index dde0d78e327..af1c908ad77 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -54,6 +54,11 @@ import ( // If no more serious errors are encountered, Unmarshal returns // an UnmarshalTypeError describing the earliest such error. // +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// // When unmarshaling quoted strings, invalid UTF-8 or // invalid UTF-16 surrogate pairs are not treated as an error. // Instead, they are replaced by the Unicode replacement diff --git a/libgo/go/encoding/json/indent.go b/libgo/go/encoding/json/indent.go index 11ef709cce7..e1bacafd6b8 100644 --- a/libgo/go/encoding/json/indent.go +++ b/libgo/go/encoding/json/indent.go @@ -69,8 +69,9 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) { // Each element in a JSON object or array begins on a new, // indented line beginning with prefix followed by one or more // copies of indent according to the indentation nesting. -// The data appended to dst has no trailing newline, to make it easier -// to embed inside other formatted JSON data. +// The data appended to dst does not begin with the prefix nor +// any indentation, and has no trailing newline, to make it +// easier to embed inside other formatted JSON data. func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { origLen := dst.Len() var scan scanner diff --git a/libgo/go/encoding/json/stream.go b/libgo/go/encoding/json/stream.go index e8d6bd4c2ce..1cb289fd843 100644 --- a/libgo/go/encoding/json/stream.go +++ b/libgo/go/encoding/json/stream.go @@ -148,7 +148,8 @@ func NewEncoder(w io.Writer) *Encoder { return &Encoder{w: w} } -// Encode writes the JSON encoding of v to the stream. +// Encode writes the JSON encoding of v to the stream, +// followed by a newline character. // // See the documentation for Marshal for details about the // conversion of Go values to JSON. diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index d9522e0b39f..8c6342013d3 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -184,10 +184,12 @@ var ( // EncodeToken does not call Flush, because usually it is part of a larger operation // such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked // during those), and those will call Flush when finished. -// // Callers that create an Encoder and then invoke EncodeToken directly, without // using Encode or EncodeElement, need to call Flush when finished to ensure // that the XML is written to the underlying writer. +// +// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token +// in the stream. func (enc *Encoder) EncodeToken(t Token) error { p := &enc.p switch t := t.(type) { @@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error { p.WriteString("-->") return p.cachedWriteError() case ProcInst: - if t.Target == "xml" || !isNameString(t.Target) { + // First token to be encoded which is also a ProcInst with target of xml + // is the xml declaration. The only ProcInst where target of xml is allowed. + if t.Target == "xml" && p.Buffered() != 0 { + return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded") + } + if !isNameString(t.Target) { return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target") } if bytes.Contains(t.Inst, endProcInst) { diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index d34118a3d8b..14f73a75d5f 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -314,6 +314,31 @@ type MarshalerStruct struct { Foo MyMarshalerAttrTest `xml:",attr"` } +type InnerStruct struct { + XMLName Name `xml:"testns outer"` +} + +type OuterStruct struct { + InnerStruct + IntAttr int `xml:"int,attr"` +} + +type OuterNamedStruct struct { + InnerStruct + XMLName Name `xml:"outerns test"` + IntAttr int `xml:"int,attr"` +} + +type OuterNamedOrderedStruct struct { + XMLName Name `xml:"outerns test"` + InnerStruct + IntAttr int `xml:"int,attr"` +} + +type OuterOuterStruct struct { + OuterStruct +} + func ifaceptr(x interface{}) interface{} { return &x } @@ -883,6 +908,22 @@ var marshalTests = []struct { ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`, Value: &MarshalerStruct{}, }, + { + ExpectXML: `<outer xmlns="testns" int="10"></outer>`, + Value: &OuterStruct{IntAttr: 10}, + }, + { + ExpectXML: `<test xmlns="outerns" int="10"></test>`, + Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10}, + }, + { + ExpectXML: `<test xmlns="outerns" int="10"></test>`, + Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10}, + }, + { + ExpectXML: `<outer xmlns="testns" int="10"></outer>`, + Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}}, + }, } func TestMarshal(t *testing.T) { @@ -1149,3 +1190,77 @@ func TestStructPointerMarshal(t *testing.T) { t.Fatal(err) } } + +var encodeTokenTests = []struct { + tok Token + want string + ok bool +}{ + {StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true}, + {StartElement{Name{"space", ""}, nil}, "", false}, + {EndElement{Name{"space", ""}}, "", false}, + {CharData("foo"), "foo", true}, + {Comment("foo"), "<!--foo-->", true}, + {Comment("foo-->"), "", false}, + {ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true}, + {ProcInst{"", []byte("Instruction")}, "", false}, + {ProcInst{"Target", []byte("Instruction?>")}, "", false}, + {Directive("foo"), "<!foo>", true}, + {Directive("foo>"), "", false}, +} + +func TestEncodeToken(t *testing.T) { + for _, tt := range encodeTokenTests { + var buf bytes.Buffer + enc := NewEncoder(&buf) + err := enc.EncodeToken(tt.tok) + switch { + case !tt.ok && err == nil: + t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok) + case tt.ok && err != nil: + t.Fatalf("enc.EncodeToken: %v", err) + case !tt.ok && err != nil: + // expected error, got one + } + if err := enc.Flush(); err != nil { + t.Fatalf("enc.EncodeToken: %v", err) + } + if got := buf.String(); got != tt.want { + t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want) + } + } +} + +func TestProcInstEncodeToken(t *testing.T) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + + if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil { + t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err) + } + + if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil { + t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst") + } + + if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil { + t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token") + } +} + +func TestDecodeEncode(t *testing.T) { + var in, out bytes.Buffer + in.WriteString(`<?xml version="1.0" encoding="UTF-8"?> +<?Target Instruction?> +<root> +</root> +`) + dec := NewDecoder(&in) + enc := NewEncoder(&out) + for tok, err := dec.Token(); err == nil; tok, err = dec.Token() { + err = enc.EncodeToken(tok) + if err != nil { + t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err) + } + } +} diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index 651d13d4d09..75b9f2ba1b2 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -284,6 +284,15 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { } } + // Load value from interface, but only if the result will be + // usefully addressable. + if val.Kind() == reflect.Interface && !val.IsNil() { + e := val.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() { + val = e + } + } + if val.Kind() == reflect.Ptr { if val.IsNil() { val.Set(reflect.New(val.Type().Elem())) diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go index 1404c900f50..01f55d0dd00 100644 --- a/libgo/go/encoding/xml/read_test.go +++ b/libgo/go/encoding/xml/read_test.go @@ -685,3 +685,30 @@ func TestUnmarshaler(t *testing.T) { t.Errorf("m=%#+v\n", m) } } + +type Pea struct { + Cotelydon string +} + +type Pod struct { + Pea interface{} `xml:"Pea"` +} + +// https://code.google.com/p/go/issues/detail?id=6836 +func TestUnmarshalIntoInterface(t *testing.T) { + pod := new(Pod) + pod.Pea = new(Pea) + xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>` + err := Unmarshal([]byte(xml), pod) + if err != nil { + t.Fatalf("failed to unmarshal %q: %v", xml, err) + } + pea, ok := pod.Pea.(*Pea) + if !ok { + t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea) + } + have, want := pea.Cotelydon, "Green stuff" + if have != want { + t.Errorf("failed to unmarshal into interface, have %q want %q", have, want) + } +} diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go index 83e65402c00..22248d20a6d 100644 --- a/libgo/go/encoding/xml/typeinfo.go +++ b/libgo/go/encoding/xml/typeinfo.go @@ -75,6 +75,9 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) { if err != nil { return nil, err } + if tinfo.xmlname == nil { + tinfo.xmlname = inner.xmlname + } for _, finfo := range inner.fields { finfo.idx = append([]int{i}, finfo.idx...) if err := addFieldInfo(typ, tinfo, &finfo); err != nil { diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go index 5b9d670024e..b473cb84584 100644 --- a/libgo/go/encoding/xml/xml.go +++ b/libgo/go/encoding/xml/xml.go @@ -200,6 +200,8 @@ type Decoder struct { } // NewDecoder creates a new XML parser reading from r. +// If r does not implement io.ByteReader, NewDecoder will +// do its own buffering. func NewDecoder(r io.Reader) *Decoder { d := &Decoder{ ns: make(map[string]string), diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go index c590782a8d2..9b6dab487cb 100644 --- a/libgo/go/expvar/expvar.go +++ b/libgo/go/expvar/expvar.go @@ -108,11 +108,11 @@ func (v *Map) String() string { var b bytes.Buffer fmt.Fprintf(&b, "{") first := true - v.Do(func(kv KeyValue) { + v.doLocked(func(kv KeyValue) { if !first { fmt.Fprintf(&b, ", ") } - fmt.Fprintf(&b, "\"%s\": %v", kv.Key, kv.Value) + fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value) first = false }) fmt.Fprintf(&b, "}") @@ -202,6 +202,12 @@ func (v *Map) AddFloat(key string, delta float64) { func (v *Map) Do(f func(KeyValue)) { v.mu.RLock() defer v.mu.RUnlock() + v.doLocked(f) +} + +// doLocked calls f for each entry in the map. +// v.mu must be held for reads. +func (v *Map) doLocked(f func(KeyValue)) { for _, k := range v.keys { f(KeyValue{k, v.m[k]}) } diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go index d2ea484935e..765e3b757e9 100644 --- a/libgo/go/expvar/expvar_test.go +++ b/libgo/go/expvar/expvar_test.go @@ -97,15 +97,15 @@ func TestMapCounter(t *testing.T) { colors.Add("red", 1) colors.Add("red", 2) colors.Add("blue", 4) - colors.AddFloat("green", 4.125) + colors.AddFloat(`green "midori"`, 4.125) if x := colors.m["red"].(*Int).i; x != 3 { t.Errorf("colors.m[\"red\"] = %v, want 3", x) } if x := colors.m["blue"].(*Int).i; x != 4 { t.Errorf("colors.m[\"blue\"] = %v, want 4", x) } - if x := colors.m["green"].(*Float).f; x != 4.125 { - t.Errorf("colors.m[\"green\"] = %v, want 3.14", x) + if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 { + t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x) } // colors.String() should be '{"red":3, "blue":4}', diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go index d3b454fefd4..cd2a165be19 100644 --- a/libgo/go/flag/flag.go +++ b/libgo/go/flag/flag.go @@ -50,7 +50,8 @@ ("-" is a non-flag argument) or after the terminator "--". Integer flags accept 1234, 0664, 0x1234 and may be negative. - Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False. + Boolean flags may be: + 1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False Duration flags accept any input valid for time.ParseDuration. The default set of command-line flags is controlled by @@ -754,7 +755,7 @@ func (f *FlagSet) parseOne() (bool, error) { if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg if has_value { if err := fv.Set(value); err != nil { - return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err) + return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err) } } else { fv.Set("true") diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go index 095fd03b23d..02642d6ae77 100644 --- a/libgo/go/fmt/doc.go +++ b/libgo/go/fmt/doc.go @@ -37,6 +37,7 @@ %e scientific notation, e.g. -1234.456e+78 %E scientific notation, e.g. -1234.456E+78 %f decimal point but no exponent, e.g. 123.456 + %F synonym for %f %g whichever of %e or %f produces more compact output %G whichever of %E or %f produces more compact output String and slice of bytes: @@ -50,23 +51,39 @@ There is no 'u' flag. Integers are printed unsigned if they have unsigned type. Similarly, there is no need to specify the size of the operand (int8, int64). - The width and precision control formatting and are in units of Unicode - code points. (This differs from C's printf where the units are numbers + Width is specified by an optional decimal number immediately following the verb. + If absent, the width is whatever is necessary to represent the value. + Precision is specified after the (optional) width by a period followed by a + decimal number. If no period is present, a default precision is used. + A period with no following number specifies a precision of zero. + Examples: + %f: default width, default precision + %9f width 9, default precision + %.2f default width, precision 2 + %9.2f width 9, precision 2 + %9.f width 9, precision 0 + + Width and precision are measured in units of Unicode code points. + (This differs from C's printf where the units are numbers of bytes.) Either or both of the flags may be replaced with the character '*', causing their values to be obtained from the next operand, which must be of type int. - For numeric values, width sets the minimum width of the field and + For most values, width is the minimum number of characters to output, + padding the formatted form with spaces if necessary. + For strings, precision is the maximum number of characters to output, + truncating if necessary. + + For floating-point values, width sets the minimum width of the field and precision sets the number of places after the decimal, if appropriate, except that for %g/%G it sets the total number of digits. For example, given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5. The default precision for %e and %f is 6; for %g it is the smallest number of digits necessary to identify the value uniquely. - For most values, width is the minimum number of characters to output, - padding the formatted form with spaces if necessary. - For strings, precision is the maximum number of characters to output, - truncating if necessary. + For complex numbers, the width and precision apply to the two + components independently and the result is parenthesized, so %f applied + to 1.2+3.4i produces (1.200000+3.400000i). Other flags: + always print a sign for numeric values; @@ -98,20 +115,33 @@ fmt.Printf("%v\n", i) will print 23. - If an operand implements interface Formatter, that interface - can be used for fine control of formatting. + Except when printed using the verbs %T and %p, special + formatting considerations apply for operands that implement + certain interfaces. In order of application: + + 1. If an operand implements the Formatter interface, it will + be invoked. Formatter provides fine control of formatting. + + 2. If the %v verb is used with the # flag (%#v) and the operand + implements the GoStringer interface, that will be invoked. If the format (which is implicitly %v for Println etc.) is valid - for a string (%s %q %v %x %X), the following two rules also apply: + for a string (%s %q %v %x %X), the following two rules apply: - 1. If an operand implements the error interface, the Error method - will be used to convert the object to a string, which will then + 3. If an operand implements the error interface, the Error method + will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any). - 2. If an operand implements method String() string, that method - will be used to convert the object to a string, which will then + 4. If an operand implements method String() string, that method + will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any). + For compound operands such as slices and structs, the format + applies to the elements of each operand, recursively, not to the + operand as a whole. Thus %q will quote each element of a slice + of strings, and %6.2f will control formatting for each element + of a floating-point array. + To avoid recursion in cases such as type X string func (x X) String() string { return Sprintf("<%s>", x) } diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index ce837ba63e8..8e6923119de 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -11,7 +11,6 @@ import ( "math" "runtime" "strings" - "sync/atomic" "testing" "time" "unicode" @@ -221,8 +220,12 @@ var fmtTests = []struct { {"%+.3e", 0.0, "+0.000e+00"}, {"%+.3e", 1.0, "+1.000e+00"}, {"%+.3f", -1.0, "-1.000"}, + {"%+.3F", -1.0, "-1.000"}, + {"%+.3F", float32(-1.0), "-1.000"}, {"%+07.2f", 1.0, "+001.00"}, {"%+07.2f", -1.0, "-001.00"}, + {"%+10.2f", +1.0, " +1.00"}, + {"%+10.2f", -1.0, " -1.00"}, {"% .3E", -1.0, "-1.000E+00"}, {"% .3e", 1.0, " 1.000e+00"}, {"%+.3g", 0.0, "+0"}, @@ -242,6 +245,8 @@ var fmtTests = []struct { {"%+.3g", 1 + 2i, "(+1+2i)"}, {"%.3e", 0i, "(0.000e+00+0.000e+00i)"}, {"%.3f", 0i, "(0.000+0.000i)"}, + {"%.3F", 0i, "(0.000+0.000i)"}, + {"%.3F", complex64(0i), "(0.000+0.000i)"}, {"%.3g", 0i, "(0+0i)"}, {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"}, {"%.3f", 1 + 2i, "(1.000+2.000i)"}, @@ -400,6 +405,8 @@ var fmtTests = []struct { {"%#v", "foo", `"foo"`}, {"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`}, {"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`}, + {"%#v", []byte(nil), "[]byte(nil)"}, + {"%#v", []int32(nil), "[]int32(nil)"}, // slices with other formats {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`}, @@ -506,9 +513,76 @@ var fmtTests = []struct { {"%0.100f", 1.0, zeroFill("1.", 100, "")}, {"%0.100f", -1.0, zeroFill("-1.", 100, "")}, - // Zero padding floats used to put the minus sign in the middle. - {"%020f", -1.0, "-000000000001.000000"}, + // Comparison of padding rules with C printf. + /* + C program: + #include <stdio.h> + + char *format[] = { + "[%.2f]", + "[% .2f]", + "[%+.2f]", + "[%7.2f]", + "[% 7.2f]", + "[%+7.2f]", + "[%07.2f]", + "[% 07.2f]", + "[%+07.2f]", + }; + + int main(void) { + int i; + for(i = 0; i < 9; i++) { + printf("%s: ", format[i]); + printf(format[i], 1.0); + printf(" "); + printf(format[i], -1.0); + printf("\n"); + } + } + + Output: + [%.2f]: [1.00] [-1.00] + [% .2f]: [ 1.00] [-1.00] + [%+.2f]: [+1.00] [-1.00] + [%7.2f]: [ 1.00] [ -1.00] + [% 7.2f]: [ 1.00] [ -1.00] + [%+7.2f]: [ +1.00] [ -1.00] + [%07.2f]: [0001.00] [-001.00] + [% 07.2f]: [ 001.00] [-001.00] + [%+07.2f]: [+001.00] [-001.00] + */ + {"%.2f", 1.0, "1.00"}, + {"%.2f", -1.0, "-1.00"}, + {"% .2f", 1.0, " 1.00"}, + {"% .2f", -1.0, "-1.00"}, + {"%+.2f", 1.0, "+1.00"}, + {"%+.2f", -1.0, "-1.00"}, + {"%7.2f", 1.0, " 1.00"}, + {"%7.2f", -1.0, " -1.00"}, + {"% 7.2f", 1.0, " 1.00"}, + {"% 7.2f", -1.0, " -1.00"}, + {"%+7.2f", 1.0, " +1.00"}, + {"%+7.2f", -1.0, " -1.00"}, + {"%07.2f", 1.0, "0001.00"}, + {"%07.2f", -1.0, "-001.00"}, + {"% 07.2f", 1.0, " 001.00"}, + {"% 07.2f", -1.0, "-001.00"}, + {"%+07.2f", 1.0, "+001.00"}, + {"%+07.2f", -1.0, "-001.00"}, + + // Complex numbers: exhaustively tested in TestComplexFormatting. + {"%7.2f", 1 + 2i, "( 1.00 +2.00i)"}, + {"%+07.2f", -1 - 2i, "(-001.00-002.00i)"}, + // Zero padding does not apply to infinities. + {"%020f", math.Inf(-1), " -Inf"}, + {"%020f", math.Inf(+1), " +Inf"}, + {"% 020f", math.Inf(-1), " -Inf"}, + {"% 020f", math.Inf(+1), " Inf"}, + {"%+020f", math.Inf(-1), " -Inf"}, + {"%+020f", math.Inf(+1), " +Inf"}, {"%20f", -1.0, " -1.000000"}, + // Make sure we can handle very large widths. {"%0100f", -1.0, zeroFill("-", 99, "1.000000")}, // Complex fmt used to leave the plus flag set for future entries in the array @@ -539,6 +613,16 @@ var fmtTests = []struct { {"%#072o", -1, zeroFill("-", 71, "1")}, {"%#072d", 1, zeroFill("", 72, "1")}, {"%#072d", -1, zeroFill("-", 71, "1")}, + + // Padding for complex numbers. Has been bad, then fixed, then bad again. + {"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"}, + {"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"}, + {"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"}, + {"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"}, + {"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"}, + {"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"}, + {"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"}, + {"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"}, } // zeroFill generates zero-filled strings of the specified width. The length @@ -584,6 +668,50 @@ func TestSprintf(t *testing.T) { } } +// TestComplexFormatting checks that a complex always formats to the same +// thing as if done by hand with two singleton prints. +func TestComplexFormatting(t *testing.T) { + var yesNo = []bool{true, false} + var signs = []float64{1, 0, -1} + for _, plus := range yesNo { + for _, zero := range yesNo { + for _, space := range yesNo { + for _, char := range "fFeEgG" { + realFmt := "%" + if zero { + realFmt += "0" + } + if space { + realFmt += " " + } + if plus { + realFmt += "+" + } + realFmt += "10.2" + realFmt += string(char) + // Imaginary part always has a sign, so force + and ignore space. + imagFmt := "%" + if zero { + imagFmt += "0" + } + imagFmt += "+" + imagFmt += "10.2" + imagFmt += string(char) + for _, realSign := range signs { + for _, imagSign := range signs { + one := Sprintf(realFmt, complex(realSign, imagSign)) + two := Sprintf("("+realFmt+imagFmt+"i)", realSign, imagSign) + if one != two { + t.Error(f, one, two) + } + } + } + } + } + } + } +} + type SE []interface{} // slice of empty; notational compactness. var reorderTests = []struct { @@ -634,69 +762,63 @@ func TestReorder(t *testing.T) { } func BenchmarkSprintfEmpty(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("") + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("") + } }) } func BenchmarkSprintfString(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%s", "hello") + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%s", "hello") + } }) } func BenchmarkSprintfInt(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%d", 5) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%d", 5) + } }) } func BenchmarkSprintfIntInt(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%d %d", 5, 6) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%d %d", 5, 6) + } }) } func BenchmarkSprintfPrefixedInt(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6) + } }) } func BenchmarkSprintfFloat(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - Sprintf("%g", 5.23184) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + Sprintf("%g", 5.23184) + } }) } func BenchmarkManyArgs(b *testing.B) { - benchmarkSprintf(b, func(buf *bytes.Buffer) { - buf.Reset() - Fprintf(buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world") + b.RunParallel(func(pb *testing.PB) { + var buf bytes.Buffer + for pb.Next() { + buf.Reset() + Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world") + } }) } -func benchmarkSprintf(b *testing.B, f func(buf *bytes.Buffer)) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - var buf bytes.Buffer - for atomic.AddInt32(&N, -1) >= 0 { - for g := 0; g < CallsPerSched; g++ { - f(&buf) - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } -} - var mallocBuf bytes.Buffer // gccgo numbers are different because gccgo does not have escape diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go index 3835aa9823a..a89c542cfb5 100644 --- a/libgo/go/fmt/format.go +++ b/libgo/go/fmt/format.go @@ -5,6 +5,7 @@ package fmt import ( + "math" "strconv" "unicode/utf8" ) @@ -360,38 +361,48 @@ func doPrec(f *fmt, def int) int { // formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...). func (f *fmt) formatFloat(v float64, verb byte, prec, n int) { - // We leave one byte at the beginning of f.intbuf for a sign if needed, - // and make it a space, which we might be able to use. - f.intbuf[0] = ' ' - slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n) - // Add a plus sign or space to the floating-point string representation if missing and required. - // The formatted number starts at slice[1]. - switch slice[1] { - case '-', '+': - // If we're zero padding, want the sign before the leading zeros. - // Achieve this by writing the sign out and padding the postive number. - if f.zero && f.widPresent && f.wid > len(slice) { - f.buf.WriteByte(slice[1]) - f.wid-- - f.pad(slice[2:]) - return + // Format number, reserving space for leading + sign if needed. + num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n) + if num[1] == '-' || num[1] == '+' { + num = num[1:] + } else { + num[0] = '+' + } + // Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros. + if math.IsInf(v, 0) { + if f.zero { + defer func() { f.zero = true }() + f.zero = false } - // We're set; drop the leading space. - slice = slice[1:] - default: - // There's no sign, but we might need one. - if f.plus { - f.buf.WriteByte('+') + } + // num is now a signed version of the number. + // If we're zero padding, want the sign before the leading zeros. + // Achieve this by writing the sign out and then padding the unsigned number. + if f.zero && f.widPresent && f.wid > len(num) { + if f.space && v >= 0 { + f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space. + f.wid-- + } else if f.plus || v < 0 { + f.buf.WriteByte(num[0]) f.wid-- - f.pad(slice[1:]) - return - } else if f.space { - // space is already there - } else { - slice = slice[1:] } + f.pad(num[1:]) + return } - f.pad(slice) + // f.space says to replace a leading + with a space. + if f.space && num[0] == '+' { + num[0] = ' ' + f.pad(num) + return + } + // Now we know the sign is attached directly to the number, if present at all. + // We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf). + if f.plus || num[0] == '-' || math.IsInf(v, 0) { + f.pad(num) + return + } + // No sign to show and the number is positive; just print the unsigned number. + f.pad(num[1:]) } // fmt_e64 formats a float64 in the form -1.23e+12. @@ -436,60 +447,46 @@ func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) } // fmt_c64 formats a complex64 according to the verb. func (f *fmt) fmt_c64(v complex64, verb rune) { - f.buf.WriteByte('(') - r := real(v) - oldPlus := f.plus - for i := 0; ; i++ { - switch verb { - case 'b': - f.fmt_fb32(r) - case 'e': - f.fmt_e32(r) - case 'E': - f.fmt_E32(r) - case 'f': - f.fmt_f32(r) - case 'g': - f.fmt_g32(r) - case 'G': - f.fmt_G32(r) - } - if i != 0 { - break - } - f.plus = true - r = imag(v) - } - f.plus = oldPlus - f.buf.Write(irparenBytes) + f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb) } // fmt_c128 formats a complex128 according to the verb. func (f *fmt) fmt_c128(v complex128, verb rune) { + f.fmt_complex(real(v), imag(v), 64, verb) +} + +// fmt_complex formats a complex number as (r+ji). +func (f *fmt) fmt_complex(r, j float64, size int, verb rune) { f.buf.WriteByte('(') - r := real(v) oldPlus := f.plus + oldSpace := f.space + oldWid := f.wid for i := 0; ; i++ { switch verb { case 'b': - f.fmt_fb64(r) + f.formatFloat(r, 'b', 0, size) case 'e': - f.fmt_e64(r) + f.formatFloat(r, 'e', doPrec(f, 6), size) case 'E': - f.fmt_E64(r) - case 'f': - f.fmt_f64(r) + f.formatFloat(r, 'E', doPrec(f, 6), size) + case 'f', 'F': + f.formatFloat(r, 'f', doPrec(f, 6), size) case 'g': - f.fmt_g64(r) + f.formatFloat(r, 'g', doPrec(f, -1), size) case 'G': - f.fmt_G64(r) + f.formatFloat(r, 'G', doPrec(f, -1), size) } if i != 0 { break } + // Imaginary part always has a sign. f.plus = true - r = imag(v) + f.space = false + f.wid = oldWid + r = j } + f.space = oldSpace f.plus = oldPlus + f.wid = oldWid f.buf.Write(irparenBytes) } diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 2f13bcd95e9..302661f4c85 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -447,7 +447,7 @@ func (p *pp) fmtFloat32(v float32, verb rune) { p.fmt.fmt_e32(v) case 'E': p.fmt.fmt_E32(v) - case 'f': + case 'f', 'F': p.fmt.fmt_f32(v) case 'g', 'v': p.fmt.fmt_g32(v) @@ -466,7 +466,7 @@ func (p *pp) fmtFloat64(v float64, verb rune) { p.fmt.fmt_e64(v) case 'E': p.fmt.fmt_E64(v) - case 'f': + case 'f', 'F': p.fmt.fmt_f64(v) case 'g', 'v': p.fmt.fmt_g64(v) @@ -523,6 +523,15 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) { func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) { if verb == 'v' || verb == 'd' { if goSyntax { + if v == nil { + if typ == nil { + p.buf.WriteString("[]byte(nil)") + } else { + p.buf.WriteString(typ.String()) + p.buf.Write(nilParenBytes) + } + return + } if typ == nil { p.buf.Write(bytesBytes) } else { diff --git a/libgo/go/go/ast/commentmap.go b/libgo/go/go/ast/commentmap.go index 1fb4867dd28..ac999d627ce 100644 --- a/libgo/go/go/ast/commentmap.go +++ b/libgo/go/go/ast/commentmap.go @@ -149,7 +149,7 @@ func NewCommentMap(fset *token.FileSet, node Node, comments []*CommentGroup) Com // set up comment reader r tmp := make([]*CommentGroup, len(comments)) - copy(tmp, comments) // don't change incomming comments + copy(tmp, comments) // don't change incoming comments sortComments(tmp) r := commentListReader{fset: fset, list: tmp} // !r.eol() because len(comments) > 0 r.next() diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go index 096028d34c3..4df0b8983ac 100644 --- a/libgo/go/go/build/build.go +++ b/libgo/go/go/build/build.go @@ -264,6 +264,7 @@ var cgoEnabled = map[string]bool{ "dragonfly/amd64": true, "freebsd/386": true, "freebsd/amd64": true, + "freebsd/arm": true, "linux/386": true, "linux/amd64": true, "linux/arm": true, @@ -291,10 +292,10 @@ func defaultContext() Context { // say "+build go1.x", and code that should only be built before Go 1.x // (perhaps it is the stub to use in that case) should say "+build !go1.x". // - // When we reach Go 1.3 the line will read - // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"} + // When we reach Go 1.4 the line will read + // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"} // and so on. - c.ReleaseTags = []string{"go1.1", "go1.2"} + c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"} switch os.Getenv("CGO_ENABLED") { case "1": @@ -1209,7 +1210,7 @@ func ArchChar(goarch string) (string, error) { switch goarch { case "386": return "8", nil - case "amd64": + case "amd64", "amd64p32": return "6", nil case "arm": return "5", nil diff --git a/libgo/go/go/build/deps_test.go b/libgo/go/go/build/deps_test.go index d238e96eaa8..3a795fdcc4b 100644 --- a/libgo/go/go/build/deps_test.go +++ b/libgo/go/go/build/deps_test.go @@ -8,6 +8,7 @@ package build import ( + "runtime" "sort" "testing" ) @@ -359,7 +360,7 @@ func allowed(pkg string) map[string]bool { } var bools = []bool{false, true} -var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "plan9", "solaris", "windows"} +var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"} var goarches = []string{"386", "amd64", "arm", "arm64"} type osPkg struct { @@ -374,6 +375,11 @@ var allowedErrors = map[osPkg]bool{ } func TestDependencies(t *testing.T) { + if runtime.GOOS == "nacl" { + // NaCl tests run in a limited file system and we do not + // provide access to every source file. + t.Skip("skipping on NaCl") + } var all []string for k := range pkgDeps { @@ -387,6 +393,9 @@ func TestDependencies(t *testing.T) { if isMacro(pkg) { continue } + if pkg == "runtime/cgo" && !ctxt.CgoEnabled { + continue + } p, err := ctxt.Import(pkg, "", 0) if err != nil { if allowedErrors[osPkg{ctxt.GOOS, pkg}] { diff --git a/libgo/go/go/build/doc.go b/libgo/go/go/build/doc.go index 83292f29f82..f17f76ccc7b 100644 --- a/libgo/go/go/build/doc.go +++ b/libgo/go/go/build/doc.go @@ -99,6 +99,7 @@ // - "cgo", if ctxt.CgoEnabled is true // - "go1.1", from Go version 1.1 onward // - "go1.2", from Go version 1.2 onward +// - "go1.3", from Go version 1.3 onward // - any additional words listed in ctxt.BuildTags // // If a file's name, after stripping the extension and a possible _test suffix, diff --git a/libgo/go/go/build/syslist.go b/libgo/go/go/build/syslist.go index 71484aa9f16..b1d5bbe4f44 100644 --- a/libgo/go/go/build/syslist.go +++ b/libgo/go/go/build/syslist.go @@ -4,5 +4,5 @@ package build -const goosList = "darwin dragonfly freebsd linux netbsd openbsd plan9 solaris windows " -const goarchList = "386 amd64 arm arm64 alpha m68k mipso32 mipsn32 mipsn64 mipso64 ppc ppc64 sparc sparc64 " +const goosList = "darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows " +const goarchList = "386 amd64 amd64p32 arm arm64 alpha m68k mipso32 mipsn32 mipsn64 mipso64 ppc ppc64 sparc sparc64 " diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go index 5c8c43e0c1a..f414ca4090e 100644 --- a/libgo/go/go/doc/comment.go +++ b/libgo/go/go/doc/comment.go @@ -45,13 +45,13 @@ func commentEscape(w io.Writer, text string, nice bool) { const ( // Regexp for Go identifiers - identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this + identRx = `[\pL_][\pL_0-9]*` // Regexp for URLs - protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):` + protocol = `https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero` hostPart = `[a-zA-Z0-9_@\-]+` - filePart = `[a-zA-Z0-9_?%#~&/\-+=]+` - urlRx = protocol + `//` + // http:// + filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen + urlRx = `(` + protocol + `)://` + // http:// hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/ filePart + `([:.,]` + filePart + `)*` ) @@ -73,6 +73,29 @@ var ( html_endh = []byte("</h3>\n") ) +// pairedParensPrefixLen returns the length of the longest prefix of s containing paired parentheses. +func pairedParensPrefixLen(s string) int { + parens := 0 + l := len(s) + for i, ch := range s { + switch ch { + case '(': + if parens == 0 { + l = i + } + parens++ + case ')': + parens-- + if parens == 0 { + l = len(s) + } else if parens < 0 { + return i + } + } + } + return l +} + // Emphasize and escape a line of text for HTML. URLs are converted into links; // if the URL also appears in the words map, the link is taken from the map (if // the corresponding map value is the empty string, the URL is not converted @@ -92,18 +115,26 @@ func emphasize(w io.Writer, line string, words map[string]string, nice bool) { // write text before match commentEscape(w, line[0:m[0]], nice) - // analyze match + // adjust match if necessary match := line[m[0]:m[1]] + if n := pairedParensPrefixLen(match); n < len(match) { + // match contains unpaired parentheses (rare); + // redo matching with shortened line for correct indices + m = matchRx.FindStringSubmatchIndex(line[:m[0]+n]) + match = match[:n] + } + + // analyze match url := "" italics := false if words != nil { - url, italics = words[string(match)] + url, italics = words[match] } if m[2] >= 0 { // match against first parenthesized sub-regexp; must be match against urlRx if !italics { // no alternative URL in words list, use match instead - url = string(match) + url = match } italics = false // don't italicize URLs } @@ -392,7 +423,9 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) { case opPre: w.Write(nl) for _, line := range b.lines { - if !isBlank(line) { + if isBlank(line) { + w.Write([]byte("\n")) + } else { w.Write([]byte(preIndent)) w.Write([]byte(line)) } diff --git a/libgo/go/go/doc/comment_test.go b/libgo/go/go/doc/comment_test.go index aa21b8d1b30..ad65c2a27f8 100644 --- a/libgo/go/go/doc/comment_test.go +++ b/libgo/go/go/doc/comment_test.go @@ -42,8 +42,9 @@ func TestIsHeading(t *testing.T) { } var blocksTests = []struct { - in string - out []block + in string + out []block + text string }{ { in: `Para 1. @@ -59,6 +60,22 @@ Para 3. pre1 Para 4. + + pre + pre1 + + pre2 + +Para 5. + + + pre + + + pre1 + pre2 + +Para 6. pre pre2 `, @@ -69,8 +86,44 @@ Para 4. {opPara, []string{"Para 3.\n"}}, {opPre, []string{"pre\n", "pre1\n"}}, {opPara, []string{"Para 4.\n"}}, + {opPre, []string{"pre\n", "pre1\n", "\n", "pre2\n"}}, + {opPara, []string{"Para 5.\n"}}, + {opPre, []string{"pre\n", "\n", "\n", "pre1\n", "pre2\n"}}, + {opPara, []string{"Para 6.\n"}}, {opPre, []string{"pre\n", "pre2\n"}}, }, + text: `. Para 1. Para 1 line 2. + +. Para 2. + + +. Section + +. Para 3. + +$ pre +$ pre1 + +. Para 4. + +$ pre +$ pre1 + +$ pre2 + +. Para 5. + +$ pre + + +$ pre1 +$ pre2 + +. Para 6. + +$ pre +$ pre2 +`, }, } @@ -83,14 +136,28 @@ func TestBlocks(t *testing.T) { } } +func TestToText(t *testing.T) { + var buf bytes.Buffer + for i, tt := range blocksTests { + ToText(&buf, tt.in, ". ", "$\t", 40) + if have := buf.String(); have != tt.text { + t.Errorf("#%d: mismatch\nhave: %s\nwant: %s\nhave vs want:\n%q\n%q", i, have, tt.text, have, tt.text) + } + buf.Reset() + } +} + var emphasizeTests = []struct { - in string - out string + in, out string }{ {"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`}, {"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`}, {"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`}, + {"http://en.wikipedia.org/wiki/Camellia_(cipher)", `<a href="http://en.wikipedia.org/wiki/Camellia_(cipher)">http://en.wikipedia.org/wiki/Camellia_(cipher)</a>`}, {"(http://www.google.com/)", `(<a href="http://www.google.com/">http://www.google.com/</a>)`}, + {"http://gmail.com)", `<a href="http://gmail.com">http://gmail.com</a>)`}, + {"((http://gmail.com))", `((<a href="http://gmail.com">http://gmail.com</a>))`}, + {"http://gmail.com ((http://gmail.com)) ()", `<a href="http://gmail.com">http://gmail.com</a> ((<a href="http://gmail.com">http://gmail.com</a>)) ()`}, {"Foo bar http://example.com/ quux!", `Foo bar <a href="http://example.com/">http://example.com/</a> quux!`}, {"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`}, {"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"}, @@ -107,3 +174,34 @@ func TestEmphasize(t *testing.T) { } } } + +var pairedParensPrefixLenTests = []struct { + in, out string +}{ + {"", ""}, + {"foo", "foo"}, + {"()", "()"}, + {"foo()", "foo()"}, + {"foo()()()", "foo()()()"}, + {"foo()((()()))", "foo()((()()))"}, + {"foo()((()()))bar", "foo()((()()))bar"}, + {"foo)", "foo"}, + {"foo))", "foo"}, + {"foo)))))", "foo"}, + {"(foo", ""}, + {"((foo", ""}, + {"(((((foo", ""}, + {"(foo)", "(foo)"}, + {"((((foo))))", "((((foo))))"}, + {"foo()())", "foo()()"}, + {"foo((()())", "foo"}, + {"foo((()())) (() foo ", "foo((()())) "}, +} + +func TestPairedParensPrefixLen(t *testing.T) { + for i, tt := range pairedParensPrefixLenTests { + if out := tt.in[:pairedParensPrefixLen(tt.in)]; out != tt.out { + t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out) + } + } +} diff --git a/libgo/go/go/doc/example.go b/libgo/go/go/doc/example.go index f4ce9f65415..c414e548ccd 100644 --- a/libgo/go/go/doc/example.go +++ b/libgo/go/go/doc/example.go @@ -255,7 +255,7 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File { } } - // Strip "Output:" commment and adjust body end position. + // Strip "Output:" comment and adjust body end position. body, comments = stripOutputComment(body, comments) // Synthesize import declaration. @@ -318,7 +318,7 @@ func playExampleFile(file *ast.File) *ast.File { return &f } -// stripOutputComment finds and removes an "Output:" commment from body +// stripOutputComment finds and removes an "Output:" comment from body // and comments, and adjusts the body block's end position. func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) { // Do nothing if no "Output:" comment found. diff --git a/libgo/go/go/parser/error_test.go b/libgo/go/go/parser/error_test.go index d4d4f909d3f..8506077cee6 100644 --- a/libgo/go/go/parser/error_test.go +++ b/libgo/go/go/parser/error_test.go @@ -59,8 +59,11 @@ func getPos(filename string, offset int) token.Pos { // ERROR comments must be of the form /* ERROR "rx" */ and rx is // a regular expression that matches the expected error message. +// The special form /* ERROR HERE "rx" */ must be used for error +// messages that appear immediately after a token, rather than at +// a token's position. // -var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`) +var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`) // expectedErrors collects the regular expressions of ERROR comments found // in files and returns them as a map of error positions to error messages. @@ -74,6 +77,7 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str // not match the position information collected by the parser s.Init(getFile(filename), src, nil, scanner.ScanComments) var prev token.Pos // position of last non-comment, non-semicolon token + var here token.Pos // position immediately after the token at position prev for { pos, tok, lit := s.Scan() @@ -82,11 +86,22 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str return errors case token.COMMENT: s := errRx.FindStringSubmatch(lit) - if len(s) == 2 { - errors[prev] = string(s[1]) + if len(s) == 3 { + pos := prev + if s[1] == "HERE" { + pos = here + } + errors[pos] = string(s[2]) } default: prev = pos + var l int // token length + if tok.IsLiteral() { + l = len(lit) + } else { + l = len(tok.String()) + } + here = prev + token.Pos(l) } } } diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go index 0f83ca93143..57da4ddcd93 100644 --- a/libgo/go/go/parser/interface.go +++ b/libgo/go/go/parser/interface.go @@ -182,6 +182,13 @@ func ParseExpr(x string) (ast.Expr, error) { p.closeScope() assert(p.topScope == nil, "unbalanced scopes") + // If a semicolon was inserted, consume it; + // report an error if there's more tokens. + if p.tok == token.SEMICOLON { + p.next() + } + p.expect(token.EOF) + if p.errors.Len() > 0 { p.errors.Sort() return nil, p.errors.Err() diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go index c3e3ee859ab..00dd532b239 100644 --- a/libgo/go/go/parser/parser.go +++ b/libgo/go/go/parser/parser.go @@ -492,6 +492,26 @@ func syncDecl(p *parser) { } } +// safePos returns a valid file position for a given position: If pos +// is valid to begin with, safePos returns pos. If pos is out-of-range, +// safePos returns the EOF position. +// +// This is hack to work around "artificial" end positions in the AST which +// are computed by adding 1 to (presumably valid) token positions. If the +// token positions are invalid due to parse errors, the resulting end position +// may be past the file's EOF position, which would lead to panics if used +// later on. +// +func (p *parser) safePos(pos token.Pos) (res token.Pos) { + defer func() { + if recover() != nil { + res = token.Pos(p.file.Base() + p.file.Size()) // EOF position + } + }() + _ = p.file.Offset(pos) // trigger a panic if position is out-of-range + return pos +} + // ---------------------------------------------------------------------------- // Identifiers @@ -679,7 +699,7 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { if n := len(list); n > 1 || !isTypeName(deref(typ)) { pos := typ.Pos() p.errorExpected(pos, "anonymous field") - typ = &ast.BadExpr{From: pos, To: list[n-1].End()} + typ = &ast.BadExpr{From: pos, To: p.safePos(list[n-1].End())} } } @@ -1337,7 +1357,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { default: // all other nodes are not proper expressions p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{From: x.Pos(), To: x.End()} + x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())} } return x } @@ -1400,7 +1420,7 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { case *ast.ArrayType: if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis { p.error(len.Pos(), "expected array length, found '...'") - x = &ast.BadExpr{From: x.Pos(), To: x.End()} + x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())} } } @@ -1686,14 +1706,14 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) { return &ast.ExprStmt{X: x[0]}, false } -func (p *parser) parseCallExpr() *ast.CallExpr { +func (p *parser) parseCallExpr(callType string) *ast.CallExpr { x := p.parseRhsOrType() // could be a conversion: (some type)(x) if call, isCall := x.(*ast.CallExpr); isCall { return call } if _, isBad := x.(*ast.BadExpr); !isBad { // only report error if it's a new one - p.errorExpected(x.Pos(), "function/method call") + p.error(p.safePos(x.End()), fmt.Sprintf("function must be invoked in %s statement", callType)) } return nil } @@ -1704,7 +1724,7 @@ func (p *parser) parseGoStmt() ast.Stmt { } pos := p.expect(token.GO) - call := p.parseCallExpr() + call := p.parseCallExpr("go") p.expectSemi() if call == nil { return &ast.BadStmt{From: pos, To: pos + 2} // len("go") @@ -1719,7 +1739,7 @@ func (p *parser) parseDeferStmt() ast.Stmt { } pos := p.expect(token.DEFER) - call := p.parseCallExpr() + call := p.parseCallExpr("defer") p.expectSemi() if call == nil { return &ast.BadStmt{From: pos, To: pos + 5} // len("defer") @@ -1770,7 +1790,7 @@ func (p *parser) makeExpr(s ast.Stmt, kind string) ast.Expr { return p.checkExpr(es.X) } p.error(s.Pos(), fmt.Sprintf("expected %s, found simple statement (missing parentheses around composite literal?)", kind)) - return &ast.BadExpr{From: s.Pos(), To: s.End()} + return &ast.BadExpr{From: s.Pos(), To: p.safePos(s.End())} } func (p *parser) parseIfStmt() *ast.IfStmt { @@ -2052,7 +2072,7 @@ func (p *parser) parseForStmt() ast.Stmt { key = as.Lhs[0] default: p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions") - return &ast.BadStmt{From: pos, To: body.End()} + return &ast.BadStmt{From: pos, To: p.safePos(body.End())} } // parseSimpleStmt returned a right-hand side that // is a single unary expression of the form "range x" @@ -2299,7 +2319,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList { p.errorExpected(base.Pos(), "(unqualified) identifier") } par.List = []*ast.Field{ - {Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}}, + {Type: &ast.BadExpr{From: recv.Pos(), To: p.safePos(recv.End())}}, } } diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go index 0a34b7e505e..2797ea518bd 100644 --- a/libgo/go/go/parser/parser_test.go +++ b/libgo/go/go/parser/parser_test.go @@ -78,7 +78,7 @@ func TestParseExpr(t *testing.T) { } // sanity check if _, ok := x.(*ast.BinaryExpr); !ok { - t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x) + t.Errorf("ParseExpr(%s): got %T, want *ast.BinaryExpr", src, x) } // a valid type expression @@ -89,17 +89,24 @@ func TestParseExpr(t *testing.T) { } // sanity check if _, ok := x.(*ast.StructType); !ok { - t.Errorf("ParseExpr(%s): got %T, expected *ast.StructType", src, x) + t.Errorf("ParseExpr(%s): got %T, want *ast.StructType", src, x) } // an invalid expression src = "a + *" _, err = ParseExpr(src) if err == nil { - t.Fatalf("ParseExpr(%s): %v", src, err) + t.Fatalf("ParseExpr(%s): got no error", src) + } + + // a valid expression followed by extra tokens is invalid + src = "a[i] := x" + _, err = ParseExpr(src) + if err == nil { + t.Fatalf("ParseExpr(%s): got no error", src) } - // it must not crash + // ParseExpr must not crash for _, src := range valids { ParseExpr(src) } diff --git a/libgo/go/go/parser/short_test.go b/libgo/go/go/parser/short_test.go index 22f79930b37..b794060998f 100644 --- a/libgo/go/go/parser/short_test.go +++ b/libgo/go/go/parser/short_test.go @@ -86,6 +86,9 @@ var invalids = []string{ `package p; func f() { for x /* ERROR "boolean or range expression" */ := []string {} }`, `package p; func f() { for i /* ERROR "boolean or range expression" */ , x = []string {} }`, `package p; func f() { for i /* ERROR "boolean or range expression" */ , x := []string {} }`, + `package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`, + `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`, + `package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`, } func TestInvalid(t *testing.T) { diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go index 583c6c37090..04b5f1a76a9 100644 --- a/libgo/go/go/printer/nodes.go +++ b/libgo/go/go/printer/nodes.go @@ -378,10 +378,6 @@ func (p *printer) setLineComment(text string) { p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}}) } -func (p *printer) isMultiLine(n ast.Node) bool { - return p.lineFor(n.End())-p.lineFor(n.Pos()) > 0 -} - func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) { lbrace := fields.Opening list := fields.List @@ -428,13 +424,14 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) if len(list) == 1 { sep = blank } - newSection := false + var line int for i, f := range list { if i > 0 { - p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection) + p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0) } extraTabs := 0 p.setComment(f.Doc) + p.recordLine(&line) if len(f.Names) > 0 { // named fields p.identList(f.Names, false) @@ -460,7 +457,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) } p.setComment(f.Comment) } - newSection = p.isMultiLine(f) } if isIncomplete { if len(list) > 0 { @@ -472,12 +468,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) } else { // interface - newSection := false + var line int for i, f := range list { if i > 0 { - p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection) + p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0) } p.setComment(f.Doc) + p.recordLine(&line) if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { // method p.expr(f.Names[0]) @@ -487,7 +484,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) p.expr(f.Type) } p.setComment(f.Comment) - newSection = p.isMultiLine(f) } if isIncomplete { if len(list) > 0 { @@ -826,10 +822,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { } p.print(x.Lbrace, token.LBRACE) p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace) - // do not insert extra line breaks because of comments before - // the closing '}' as it might break the code if there is no - // trailing ',' - p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak) + // do not insert extra line break following a /*-style comment + // before the closing '}' as it might break the code if there + // is no trailing ',' + mode := noExtraLinebreak + // do not insert extra blank following a /*-style comment + // before the closing '}' unless the literal is empty + if len(x.Elts) > 0 { + mode |= noExtraBlank + } + p.print(mode, x.Rbrace, token.RBRACE, mode) case *ast.Ellipsis: p.print(token.ELLIPSIS) @@ -901,20 +903,31 @@ func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) { if nindent > 0 { p.print(indent) } - multiLine := false + var line int i := 0 for _, s := range list { // ignore empty statements (was issue 3466) if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty { - // _indent == 0 only for lists of switch/select case clauses; + // nindent == 0 only for lists of switch/select case clauses; // in those cases each clause is a new section if len(p.output) > 0 { // only print line break if we are not at the beginning of the output // (i.e., we are not printing only a partial program) - p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || multiLine) + p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0) } + p.recordLine(&line) p.stmt(s, nextIsRBrace && i == len(list)-1) - multiLine = p.isMultiLine(s) + // labeled statements put labels on a separate line, but here + // we only care about the start line of the actual statement + // without label - correct line for each label + for t := s; ; { + lt, _ := t.(*ast.LabeledStmt) + if lt == nil { + break + } + line++ + t = lt.Stmt + } i++ } } @@ -1375,22 +1388,22 @@ func (p *printer) genDecl(d *ast.GenDecl) { // two or more grouped const/var declarations: // determine if the type column must be kept keepType := keepTypeColumn(d.Specs) - newSection := false + var line int for i, s := range d.Specs { if i > 0 { - p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection) + p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0) } + p.recordLine(&line) p.valueSpec(s.(*ast.ValueSpec), keepType[i]) - newSection = p.isMultiLine(s) } } else { - newSection := false + var line int for i, s := range d.Specs { if i > 0 { - p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection) + p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0) } + p.recordLine(&line) p.spec(s, n, false) - newSection = p.isMultiLine(s) } } p.print(unindent, formfeed) @@ -1448,13 +1461,16 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int { // opening and closing brace are on different lines - don't make it a one-liner return maxSize + 1 } - if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) { - // too many statements or there is a comment inside - don't make it a one-liner + if len(b.List) > 5 { + // too many statements - don't make it a one-liner return maxSize + 1 } // otherwise, estimate body size - bodySize := 0 + bodySize := p.commentSizeBefore(p.posFor(pos2)) for i, s := range b.List { + if bodySize > maxSize { + break // no need to continue + } if i > 0 { bodySize += 2 // space for a semicolon and blank } @@ -1488,7 +1504,7 @@ func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) { } p.print(blank) } - p.print(b.Rbrace, token.RBRACE) + p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak) return } diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go index e06d2edfb21..280c697a0dd 100644 --- a/libgo/go/go/printer/printer.go +++ b/libgo/go/go/printer/printer.go @@ -39,9 +39,17 @@ const ( type pmode int const ( - noExtraLinebreak pmode = 1 << iota + noExtraBlank pmode = 1 << iota // disables extra blank after /*-style comment + noExtraLinebreak // disables extra line break after /*-style comment ) +type commentInfo struct { + cindex int // current comment index + comment *ast.CommentGroup // = printer.comments[cindex]; or nil + commentOffset int // = printer.posFor(printer.comments[cindex].List[0].Pos()).Offset; or infinity + commentNewline bool // true if the comment group contains newlines +} + type printer struct { // Configuration (does not change after initialization) Config @@ -52,7 +60,8 @@ type printer struct { indent int // current indentation mode pmode // current printer mode impliedSemi bool // if set, a linebreak implies a semicolon - lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace) + lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace) + prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL wsbuf []whiteSpace // delayed white space // Positions @@ -61,19 +70,17 @@ type printer struct { // white space). If there's a difference and SourcePos is set in // ConfigMode, //line comments are used in the output to restore // original source positions for a reader. - pos token.Position // current position in AST (source) space - out token.Position // current position in output space - last token.Position // value of pos after calling writeString + pos token.Position // current position in AST (source) space + out token.Position // current position in output space + last token.Position // value of pos after calling writeString + linePtr *int // if set, record out.Line for the next token in *linePtr // The list of all source comments, in order of appearance. comments []*ast.CommentGroup // may be nil - cindex int // current comment index useNodeComments bool // if not set, ignore lead and line comments of nodes // Information about p.comments[p.cindex]; set up by nextComment. - comment *ast.CommentGroup // = p.comments[p.cindex]; or nil - commentOffset int // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity - commentNewline bool // true if the comment group contains newlines + commentInfo // Cache of already computed node sizes. nodeSizes map[ast.Node]int @@ -93,6 +100,14 @@ func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node] p.cachedPos = -1 } +func (p *printer) internalError(msg ...interface{}) { + if debug { + fmt.Print(p.pos.String() + ": ") + fmt.Println(msg...) + panic("go/printer") + } +} + // commentsHaveNewline reports whether a list of comments belonging to // an *ast.CommentGroup contains newlines. Because the position information // may only be partially correct, we also have to read the comment text. @@ -129,12 +144,49 @@ func (p *printer) nextComment() { p.commentOffset = infinity } -func (p *printer) internalError(msg ...interface{}) { - if debug { - fmt.Print(p.pos.String() + ": ") - fmt.Println(msg...) - panic("go/printer") +// commentBefore returns true iff the current comment group occurs +// before the next position in the source code and printing it does +// not introduce implicit semicolons. +// +func (p *printer) commentBefore(next token.Position) bool { + return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline) +} + +// commentSizeBefore returns the estimated size of the +// comments on the same line before the next position. +// +func (p *printer) commentSizeBefore(next token.Position) int { + // save/restore current p.commentInfo (p.nextComment() modifies it) + defer func(info commentInfo) { + p.commentInfo = info + }(p.commentInfo) + + size := 0 + for p.commentBefore(next) { + for _, c := range p.comment.List { + size += len(c.Text) + } + p.nextComment() } + return size +} + +// recordLine records the output line number for the next non-whitespace +// token in *linePtr. It is used to compute an accurate line number for a +// formatted construct, independent of pending (not yet emitted) whitespace +// or comments. +// +func (p *printer) recordLine(linePtr *int) { + p.linePtr = linePtr +} + +// linesFrom returns the number of output lines between the current +// output line and the line argument, ignoring any pending (not yet +// emitted) whitespace or comments. It is used to compute an accurate +// size (in number of lines) for a formatted construct. +// +func (p *printer) linesFrom(line int) int { + return p.out.Line - line } func (p *printer) posFor(pos token.Pos) token.Position { @@ -675,10 +727,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro if last != nil { // if the last comment is a /*-style comment and the next item - // follows on the same line but is not a comma or a "closing" - // token, add an extra blank for separation - if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA && - tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE { + // follows on the same line but is not a comma, and not a "closing" + // token immediately following its corresponding "opening" token, + // add an extra blank for separation unless explicitly disabled + if p.mode&noExtraBlank == 0 && + last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && + tok != token.COMMA && + (tok != token.RPAREN || p.prevOpen == token.LPAREN) && + (tok != token.RBRACK || p.prevOpen == token.LBRACK) { p.writeByte(' ', 1) } // ensure that there is a line break after a //-style comment, @@ -735,12 +791,8 @@ func (p *printer) writeWhitespace(n int) { } // shift remaining entries down - i := 0 - for ; n < len(p.wsbuf); n++ { - p.wsbuf[i] = p.wsbuf[n] - i++ - } - p.wsbuf = p.wsbuf[0:i] + l := copy(p.wsbuf, p.wsbuf[n:]) + p.wsbuf = p.wsbuf[:l] } // ---------------------------------------------------------------------------- @@ -790,6 +842,17 @@ func (p *printer) print(args ...interface{}) { var isLit bool var impliedSemi bool // value for p.impliedSemi after this arg + // record previous opening token, if any + switch p.lastTok { + case token.ILLEGAL: + // ignore (white space) + case token.LPAREN, token.LBRACK: + p.prevOpen = p.lastTok + default: + // other tokens followed any opening token + p.prevOpen = token.ILLEGAL + } + switch x := arg.(type) { case pmode: // toggle printer mode @@ -899,19 +962,17 @@ func (p *printer) print(args ...interface{}) { } } + // the next token starts now - record its line number if requested + if p.linePtr != nil { + *p.linePtr = p.out.Line + p.linePtr = nil + } + p.writeString(next, data, isLit) p.impliedSemi = impliedSemi } } -// commentBefore returns true iff the current comment group occurs -// before the next position in the source code and printing it does -// not introduce implicit semicolons. -// -func (p *printer) commentBefore(next token.Position) (result bool) { - return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline) -} - // flush prints any pending comments and whitespace occurring textually // before the position of the next token tok. The flush result indicates // if a newline was written or if a formfeed was dropped from the whitespace diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go index 8454ac12b9e..306928a69a2 100644 --- a/libgo/go/go/printer/printer_test.go +++ b/libgo/go/go/printer/printer_test.go @@ -63,7 +63,7 @@ func format(src []byte, mode checkMode) ([]byte, error) { return nil, fmt.Errorf("print: %s", err) } - // make sure formated output is syntactically correct + // make sure formatted output is syntactically correct res := buf.Bytes() if _, err := parser.ParseFile(fset, "", res, 0); err != nil { return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes()) @@ -179,7 +179,7 @@ func check(t *testing.T, source, golden string, mode checkMode) { // test running past time out t.Errorf("%s: running too slowly", source) case <-cc: - // test finished within alloted time margin + // test finished within allotted time margin } } @@ -212,7 +212,7 @@ func TestFiles(t *testing.T) { } } -// TestLineComments, using a simple test case, checks that consequtive line +// TestLineComments, using a simple test case, checks that consecutive line // comments are properly terminated with a newline even if the AST position // information is incorrect. // diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden index 610a42a68bd..b1af7958a96 100644 --- a/libgo/go/go/printer/testdata/comments.golden +++ b/libgo/go/go/printer/testdata/comments.golden @@ -494,16 +494,21 @@ func _() { func _( /* this */ x /* is */ /* an */ int) { } -func _( /* no params */) {} +func _( /* no params - extra blank before and after comment */ ) {} +func _(a, b int /* params - no extra blank after comment */) {} + +func _() { f( /* no args - extra blank before and after comment */ ) } +func _() { f(a, b /* args - no extra blank after comment */) } func _() { - f( /* no args */) + f( /* no args - extra blank before and after comment */ ) + f(a, b /* args - no extra blank after comment */) } func ( /* comment1 */ T /* comment2 */) _() {} -func _() { /* one-line functions with comments are formatted as multi-line functions */ -} +func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ } +func _() { x := 0; /* comment */ y = x /* comment */ } func _() { _ = 0 diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input index d121dd4be77..983e2b2c97e 100644 --- a/libgo/go/go/printer/testdata/comments.input +++ b/libgo/go/go/printer/testdata/comments.input @@ -500,15 +500,21 @@ func _() { func _(/* this */x/* is *//* an */ int) { } -func _(/* no params */) {} +func _(/* no params - extra blank before and after comment */) {} +func _(a, b int /* params - no extra blank after comment */) {} + +func _() { f(/* no args - extra blank before and after comment */) } +func _() { f(a, b /* args - no extra blank after comment */) } func _() { - f(/* no args */) + f(/* no args - extra blank before and after comment */) + f(a, b /* args - no extra blank after comment */) } func (/* comment1 */ T /* comment2 */) _() {} -func _() { /* one-line functions with comments are formatted as multi-line functions */ } +func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ } +func _() { x := 0; /* comment */ y = x /* comment */ } func _() { _ = 0 diff --git a/libgo/go/go/printer/testdata/comments2.golden b/libgo/go/go/printer/testdata/comments2.golden index d3b50bf3e05..7676a26c125 100644 --- a/libgo/go/go/printer/testdata/comments2.golden +++ b/libgo/go/go/printer/testdata/comments2.golden @@ -77,3 +77,29 @@ func main() { println("test") } } + +func issue5623() { +L: + _ = yyyyyyyyyyyyyyyy // comment - should be aligned + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */ + + _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */ + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment + +LLLLLLL: + _ = yyyyyyyyyyyyyyyy // comment - should be aligned + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment + +LL: +LLLLL: + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */ + _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */ + + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment + _ = yyyyyyyyyyyyyyyy // comment - should be aligned + + // test case from issue +label: + mask := uint64(1)<<c - 1 // Allocation mask + used := atomic.LoadUint64(&h.used) // Current allocations +} diff --git a/libgo/go/go/printer/testdata/comments2.input b/libgo/go/go/printer/testdata/comments2.input index 6f8c85c94aa..4a055c82772 100644 --- a/libgo/go/go/printer/testdata/comments2.input +++ b/libgo/go/go/printer/testdata/comments2.input @@ -76,4 +76,30 @@ prints test 5 times for i := 0; i < 5; i++ { println("test") } -}
\ No newline at end of file +} + +func issue5623() { +L: + _ = yyyyyyyyyyyyyyyy // comment - should be aligned + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */ + + _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */ + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment + +LLLLLLL: + _ = yyyyyyyyyyyyyyyy // comment - should be aligned + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment + +LL: +LLLLL: + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */ + _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */ + + _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment + _ = yyyyyyyyyyyyyyyy // comment - should be aligned + +// test case from issue +label: + mask := uint64(1)<<c - 1 // Allocation mask + used := atomic.LoadUint64(&h.used) // Current allocations +} diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden index 0331615e519..a27f21fc8ce 100644 --- a/libgo/go/go/printer/testdata/declarations.golden +++ b/libgo/go/go/printer/testdata/declarations.golden @@ -397,6 +397,21 @@ func _() { } } +// use the formatted output rather than the input to decide when to align +// (was issue 4505) +const ( + short = 2 * (1 + 2) + aMuchLongerName = 3 +) + +var ( + short = X{} + aMuchLongerName = X{} + + x1 = X{} // foo + x2 = X{} // foo +) + func _() { type ( xxxxxx int @@ -723,7 +738,8 @@ func _() int { } // making function declarations safe for new semicolon rules -func _() { /* multi-line func because of comment */ +func _() { /* single-line function because of "short-ish" comment */ } +func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */ } func _() { diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input index dbdbdfe7422..d9951d3865f 100644 --- a/libgo/go/go/printer/testdata/declarations.input +++ b/libgo/go/go/printer/testdata/declarations.input @@ -409,6 +409,24 @@ func _() { } } +// use the formatted output rather than the input to decide when to align +// (was issue 4505) +const ( + short = 2 * ( + 1 + 2) + aMuchLongerName = 3 +) + +var ( + short = X{ + } + aMuchLongerName = X{} + + x1 = X{} // foo + x2 = X{ + } // foo +) + func _() { type ( xxxxxx int @@ -737,7 +755,8 @@ func _() int { // making function declarations safe for new semicolon rules -func _() { /* multi-line func because of comment */ } +func _() { /* single-line function because of "short-ish" comment */ } +func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */ } func _() { /* multi-line func because block is on multiple lines */ } diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go index 25588ba3b0c..cec82ea10ef 100644 --- a/libgo/go/go/scanner/scanner.go +++ b/libgo/go/go/scanner/scanner.go @@ -148,11 +148,14 @@ func (s *Scanner) interpretLineComment(text []byte) { // get filename and line number, if any if i := bytes.LastIndex(text, []byte{':'}); i > 0 { if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 { - // valid //line filename:line comment; - filename := filepath.Clean(string(text[len(prefix):i])) - if !filepath.IsAbs(filename) { - // make filename relative to current directory - filename = filepath.Join(s.dir, filename) + // valid //line filename:line comment + filename := string(bytes.TrimSpace(text[len(prefix):i])) + if filename != "" { + filename = filepath.Clean(filename) + if !filepath.IsAbs(filename) { + // make filename relative to current directory + filename = filepath.Join(s.dir, filename) + } } // update scanner position s.file.AddLineInfo(s.lineOffset+len(text)+1, filename, line) // +len(text)+1 since comment applies to next line diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go index e0d0b54f68e..fc450d8a6eb 100644 --- a/libgo/go/go/scanner/scanner_test.go +++ b/libgo/go/go/scanner/scanner_test.go @@ -493,9 +493,9 @@ var segments = []segment{ {"\nline3 //line File1.go:100", filepath.Join("dir", "TestLineComments"), 3}, // bad line comment, ignored {"\nline4", filepath.Join("dir", "TestLineComments"), 4}, {"\n//line File1.go:100\n line100", filepath.Join("dir", "File1.go"), 100}, + {"\n//line \t :42\n line1", "", 42}, {"\n//line File2.go:200\n line200", filepath.Join("dir", "File2.go"), 200}, - {"\n//line :1\n line1", "dir", 1}, - {"\n//line foo:42\n line42", filepath.Join("dir", "foo"), 42}, + {"\n//line foo\t:42\n line42", filepath.Join("dir", "foo"), 42}, {"\n //line foo:42\n line44", filepath.Join("dir", "foo"), 44}, // bad line comment, ignored {"\n//line foo 42\n line46", filepath.Join("dir", "foo"), 46}, // bad line comment, ignored {"\n//line foo:42 extra text\n line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored diff --git a/libgo/go/hash/crc32/crc32_amd64.go b/libgo/go/hash/crc32/crc32_amd64x.go index b5bc6d3cf07..b7e359930a4 100644 --- a/libgo/go/hash/crc32/crc32_amd64.go +++ b/libgo/go/hash/crc32/crc32_amd64x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build amd64 amd64p32 + package crc32 // This file contains the code to call the SSE 4.2 version of the Castagnoli diff --git a/libgo/go/html/template/attr.go b/libgo/go/html/template/attr.go index 3ea02880d45..d65d340073d 100644 --- a/libgo/go/html/template/attr.go +++ b/libgo/go/html/template/attr.go @@ -90,7 +90,7 @@ var attrTypeMap = map[string]contentType{ "name": contentTypePlain, "novalidate": contentTypeUnsafe, // Skip handler names from - // http://www.w3.org/TR/html5/Overview.html#event-handlers-on-elements-document-objects-and-window-objects + // http://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects // since we have special handling in attrType. "open": contentTypePlain, "optimum": contentTypePlain, @@ -160,7 +160,7 @@ func attrType(name string) contentType { // Heuristics to prevent "javascript:..." injection in custom // data attributes and custom attributes like g:tweetUrl. - // http://www.w3.org/TR/html5/elements.html#embedding-custom-non-visible-data-with-the-data-attributes: + // http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes // "Custom data attributes are intended to store custom data // private to the page or application, for which there are no // more appropriate attributes or elements." diff --git a/libgo/go/html/template/content.go b/libgo/go/html/template/content.go index 41b1116a661..3715ed5c938 100644 --- a/libgo/go/html/template/content.go +++ b/libgo/go/html/template/content.go @@ -16,7 +16,8 @@ type ( // 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`. // 3. CSS3 declaration productions, such as `color: red; margin: 2px`. // 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`. - // See http://www.w3.org/TR/css3-syntax/#style + // See http://www.w3.org/TR/css3-syntax/#parsing and + // https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style CSS string // HTML encapsulates a known safe HTML document fragment. diff --git a/libgo/go/html/template/context.go b/libgo/go/html/template/context.go index eb47e2be3c7..59e794d6861 100644 --- a/libgo/go/html/template/context.go +++ b/libgo/go/html/template/context.go @@ -13,7 +13,7 @@ import ( // // The zero value of type context is the start context for a template that // produces an HTML fragment as defined at -// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments +// http://www.w3.org/TR/html5/syntax.html#the-end // where the context element is null. type context struct { state state @@ -96,7 +96,7 @@ const ( // stateHTMLCmt occurs inside an <!-- HTML comment -->. stateHTMLCmt // stateRCDATA occurs inside an RCDATA element (<textarea> or <title>) - // as described at http://dev.w3.org/html5/spec/syntax.html#elements-0 + // as described at http://www.w3.org/TR/html5/syntax.html#elements-0 stateRCDATA // stateAttr occurs inside an HTML attribute whose content is text. stateAttr diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go index 9ae9749db0c..4e379828d4c 100644 --- a/libgo/go/html/template/escape.go +++ b/libgo/go/html/template/escape.go @@ -40,10 +40,14 @@ func escapeTemplates(tmpl *Template, names ...string) error { } return err } - tmpl.escaped = true - tmpl.Tree = tmpl.text.Tree } e.commit() + for _, name := range names { + if t := tmpl.set[name]; t != nil { + t.escaped = true + t.Tree = t.text.Tree + } + } return nil } @@ -207,6 +211,18 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { return c } +// allIdents returns the names of the identifiers under the Ident field of the node, +// which might be a singleton (Identifier) or a slice (Field). +func allIdents(node parse.Node) []string { + switch node := node.(type) { + case *parse.IdentifierNode: + return []string{node.Ident} + case *parse.FieldNode: + return node.Ident + } + panic("unidentified node type in allIdents") +} + // ensurePipelineContains ensures that the pipeline has commands with // the identifiers in s in order. // If the pipeline already has some of the sanitizers, do not interfere. @@ -229,27 +245,31 @@ func ensurePipelineContains(p *parse.PipeNode, s []string) { idents = p.Cmds[i+1:] } dups := 0 - for _, id := range idents { - if escFnsEq(s[dups], (id.Args[0].(*parse.IdentifierNode)).Ident) { - dups++ - if dups == len(s) { - return + for _, idNode := range idents { + for _, ident := range allIdents(idNode.Args[0]) { + if escFnsEq(s[dups], ident) { + dups++ + if dups == len(s) { + return + } } } } newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups) copy(newCmds, p.Cmds) // Merge existing identifier commands with the sanitizers needed. - for _, id := range idents { - pos := id.Args[0].Position() - i := indexOfStr((id.Args[0].(*parse.IdentifierNode)).Ident, s, escFnsEq) - if i != -1 { - for _, name := range s[:i] { - newCmds = appendCmd(newCmds, newIdentCmd(name, pos)) + for _, idNode := range idents { + pos := idNode.Args[0].Position() + for _, ident := range allIdents(idNode.Args[0]) { + i := indexOfStr(ident, s, escFnsEq) + if i != -1 { + for _, name := range s[:i] { + newCmds = appendCmd(newCmds, newIdentCmd(name, pos)) + } + s = s[i+1:] } - s = s[i+1:] } - newCmds = appendCmd(newCmds, id) + newCmds = appendCmd(newCmds, idNode) } // Create any remaining sanitizers. for _, name := range s { @@ -664,7 +684,7 @@ func contextAfterText(c context, s []byte) (context, int) { i = len(s) } if c.delim == delimSpaceOrTagEnd { - // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state + // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state // lists the runes below as error characters. // Error out because HTML parsers may differ on whether // "<a id= onclick=f(" ends inside id's or onclick's value, diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go index 58383a6cd4e..3ccf93ece01 100644 --- a/libgo/go/html/template/escape_test.go +++ b/libgo/go/html/template/escape_test.go @@ -1649,6 +1649,38 @@ func TestEmptyTemplate(t *testing.T) { } } +type Issue7379 int + +func (Issue7379) SomeMethod(x int) string { + return fmt.Sprintf("<%d>", x) +} + +// This is a test for issue 7379: type assertion error caused panic, and then +// the code to handle the panic breaks escaping. It's hard to see the second +// problem once the first is fixed, but its fix is trivial so we let that go. See +// the discussion for issue 7379. +func TestPipeToMethodIsEscaped(t *testing.T) { + tmpl := Must(New("x").Parse("<html>{{0 | .SomeMethod}}</html>\n")) + tryExec := func() string { + defer func() { + panicValue := recover() + if panicValue != nil { + t.Errorf("panicked: %v\n", panicValue) + } + }() + var b bytes.Buffer + tmpl.Execute(&b, Issue7379(0)) + return b.String() + } + for i := 0; i < 3; i++ { + str := tryExec() + const expect = "<html><0></html>\n" + if str != expect { + t.Errorf("expected %q got %q", expect, str) + } + } +} + func BenchmarkEscapedExecute(b *testing.B) { tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`)) var buf bytes.Buffer diff --git a/libgo/go/html/template/html.go b/libgo/go/html/template/html.go index f25f1074c7b..9c069efd1d9 100644 --- a/libgo/go/html/template/html.go +++ b/libgo/go/html/template/html.go @@ -50,12 +50,12 @@ func htmlEscaper(args ...interface{}) string { // htmlReplacementTable contains the runes that need to be escaped // inside a quoted attribute value or in a text node. var htmlReplacementTable = []string{ - // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state: " + // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state // U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT // CHARACTER character to the current attribute's value. // " // and similarly - // http://www.w3.org/TR/html5/tokenization.html#before-attribute-value-state + // http://www.w3.org/TR/html5/syntax.html#before-attribute-value-state 0: "\uFFFD", '"': """, '&': "&", diff --git a/libgo/go/html/template/js.go b/libgo/go/html/template/js.go index d594e0ad711..999a61ed078 100644 --- a/libgo/go/html/template/js.go +++ b/libgo/go/html/template/js.go @@ -99,7 +99,7 @@ func nextJSCtx(s []byte, preceding jsCtx) jsCtx { return jsCtxDivOp } -// regexPrecederKeywords is a set of reserved JS keywords that can precede a +// regexpPrecederKeywords is a set of reserved JS keywords that can precede a // regular expression in JS source. var regexpPrecederKeywords = map[string]bool{ "break": true, diff --git a/libgo/go/html/template/template.go b/libgo/go/html/template/template.go index 11cc34a50a3..d389658979a 100644 --- a/libgo/go/html/template/template.go +++ b/libgo/go/html/template/template.go @@ -62,6 +62,10 @@ func (t *Template) escape() error { // Execute applies a parsed template to the specified data object, // writing the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel. func (t *Template) Execute(wr io.Writer, data interface{}) error { if err := t.escape(); err != nil { return err @@ -71,6 +75,10 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error { // ExecuteTemplate applies the template associated with t that has the given // name to the specified data object and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel. func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { tmpl, err := t.lookupAndEscapeTemplate(name) if err != nil { diff --git a/libgo/go/image/jpeg/huffman.go b/libgo/go/image/jpeg/huffman.go index 9b731fdc4fa..f53d873a538 100644 --- a/libgo/go/image/jpeg/huffman.go +++ b/libgo/go/image/jpeg/huffman.go @@ -37,6 +37,9 @@ func (d *decoder) ensureNBits(n int) error { for d.b.n < n { c, err := d.r.ReadByte() if err != nil { + if err == io.EOF { + return FormatError("short Huffman data") + } return err } d.b.a = d.b.a<<8 | uint32(c) @@ -50,6 +53,9 @@ func (d *decoder) ensureNBits(n int) error { if c == 0xff { c, err = d.r.ReadByte() if err != nil { + if err == io.EOF { + return FormatError("short Huffman data") + } return err } if c != 0x00 { diff --git a/libgo/go/image/jpeg/reader_test.go b/libgo/go/image/jpeg/reader_test.go index e951e038c06..926bb043448 100644 --- a/libgo/go/image/jpeg/reader_test.go +++ b/libgo/go/image/jpeg/reader_test.go @@ -28,6 +28,7 @@ func TestDecodeProgressive(t *testing.T) { "../testdata/video-001.q50.444", "../testdata/video-005.gray.q50", "../testdata/video-005.gray.q50.2x2", + "../testdata/video-001.separate.dc.progression", } for _, tc := range testCases { m0, err := decodeFile(tc + ".jpeg") @@ -44,6 +45,12 @@ func TestDecodeProgressive(t *testing.T) { t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds()) continue } + // All of the video-*.jpeg files are 150x103. + if m0.Bounds() != image.Rect(0, 0, 150, 103) { + t.Errorf("%s: bad bounds: %v", tc, m0.Bounds()) + continue + } + switch m0 := m0.(type) { case *image.YCbCr: m1 := m1.(*image.YCbCr) @@ -84,18 +91,15 @@ func decodeFile(filename string) (image.Image, error) { // check checks that the two pix data are equal, within the given bounds. func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error { - if len(pix0) != len(pix1) { - return fmt.Errorf("len(pix) %d and %d differ", len(pix0), len(pix1)) - } - if stride0 != stride1 { - return fmt.Errorf("strides %d and %d differ", stride0, stride1) + if stride0 <= 0 || stride0%8 != 0 { + return fmt.Errorf("bad stride %d", stride0) } - if stride0%8 != 0 { - return fmt.Errorf("stride %d is not a multiple of 8", stride0) + if stride1 <= 0 || stride1%8 != 0 { + return fmt.Errorf("bad stride %d", stride1) } // Compare the two pix data, one 8x8 block at a time. - for y := 0; y < len(pix0)/stride0; y += 8 { - for x := 0; x < stride0; x += 8 { + for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 { + for x := 0; x < stride0 && x < stride1; x += 8 { if x >= bounds.Max.X || y >= bounds.Max.Y { // We don't care if the two pix data differ if the 8x8 block is // entirely outside of the image's bounds. For example, this can @@ -108,8 +112,9 @@ func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) erro for j := 0; j < 8; j++ { for i := 0; i < 8; i++ { - index := (y+j)*stride0 + (x + i) - if pix0[index] != pix1[index] { + index0 := (y+j)*stride0 + (x + i) + index1 := (y+j)*stride1 + (x + i) + if pix0[index0] != pix1[index1] { return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y, pixString(pix0, stride0, x, y), pixString(pix1, stride1, x, y), diff --git a/libgo/go/image/jpeg/scan.go b/libgo/go/image/jpeg/scan.go index a69ed17489c..559235d5127 100644 --- a/libgo/go/image/jpeg/scan.go +++ b/libgo/go/image/jpeg/scan.go @@ -141,25 +141,30 @@ func (d *decoder) processSOS(n int) error { for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; j++ { // The blocks are traversed one MCU at a time. For 4:2:0 chroma // subsampling, there are four Y 8x8 blocks in every 16x16 MCU. + // // For a baseline 32x16 pixel image, the Y blocks visiting order is: // 0 1 4 5 // 2 3 6 7 // - // For progressive images, the DC data blocks (zigStart == 0) are traversed - // as above, but AC data blocks are traversed left to right, top to bottom: + // For progressive images, the interleaved scans (those with nComp > 1) + // are traversed as above, but non-interleaved scans are traversed left + // to right, top to bottom: // 0 1 2 3 // 4 5 6 7 + // Only DC scans (zigStart == 0) can be interleaved. AC scans must have + // only one component. // - // To further complicate matters, there is no AC data for any blocks that - // are inside the image at the MCU level but outside the image at the pixel - // level. For example, a 24x16 pixel 4:2:0 progressive image consists of - // two 16x16 MCUs. The earlier scans will process 8 Y blocks: + // To further complicate matters, for non-interleaved scans, there is no + // data for any blocks that are inside the image at the MCU level but + // outside the image at the pixel level. For example, a 24x16 pixel 4:2:0 + // progressive image consists of two 16x16 MCUs. The interleaved scans + // will process 8 Y blocks: // 0 1 4 5 // 2 3 6 7 - // The later scans will process only 6 Y blocks: + // The non-interleaved scans will process only 6 Y blocks: // 0 1 2 // 3 4 5 - if zigStart == 0 { + if nComp != 1 { mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my if h0 == 1 { my0 += j diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go index a6bf86ede65..dfe2991024d 100644 --- a/libgo/go/image/png/reader.go +++ b/libgo/go/image/png/reader.go @@ -505,8 +505,14 @@ func (d *decoder) decode() (image.Image, error) { } // Check for EOF, to verify the zlib checksum. - n, err := r.Read(pr[:1]) - if err != io.EOF { + n := 0 + for i := 0; n == 0 && err == nil; i++ { + if i == 100 { + return nil, io.ErrNoProgress + } + n, err = r.Read(pr[:1]) + } + if err != nil && err != io.EOF { return nil, FormatError(err.Error()) } if n != 0 || d.idatLength != 0 { diff --git a/libgo/go/image/testdata/video-001.separate.dc.progression.jpeg b/libgo/go/image/testdata/video-001.separate.dc.progression.jpeg Binary files differnew file mode 100644 index 00000000000..107f0fa0cd2 --- /dev/null +++ b/libgo/go/image/testdata/video-001.separate.dc.progression.jpeg diff --git a/libgo/go/image/testdata/video-001.separate.dc.progression.progressive.jpeg b/libgo/go/image/testdata/video-001.separate.dc.progression.progressive.jpeg Binary files differnew file mode 100644 index 00000000000..a1d493ef809 --- /dev/null +++ b/libgo/go/image/testdata/video-001.separate.dc.progression.progressive.jpeg diff --git a/libgo/go/image/testdata/video-005.gray.gif b/libgo/go/image/testdata/video-005.gray.gif Binary files differnew file mode 100644 index 00000000000..23350d6dc12 --- /dev/null +++ b/libgo/go/image/testdata/video-005.gray.gif diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go index f7073ffc068..022fdb67645 100644 --- a/libgo/go/io/io.go +++ b/libgo/go/io/io.go @@ -74,6 +74,7 @@ type Reader interface { // It returns the number of bytes written from p (0 <= n <= len(p)) // and any error encountered that caused the write to stop early. // Write must return a non-nil error if it returns n < len(p). +// Write must not modify the slice data, even temporarily. type Writer interface { Write(p []byte) (n int, err error) } diff --git a/libgo/go/io/multi.go b/libgo/go/io/multi.go index ab8dd5d3b40..e26cc53e9ee 100644 --- a/libgo/go/io/multi.go +++ b/libgo/go/io/multi.go @@ -29,7 +29,9 @@ func (mr *multiReader) Read(p []byte) (n int, err error) { // inputs have returned EOF, Read will return EOF. If any of the readers // return a non-nil, non-EOF error, Read will return that error. func MultiReader(readers ...Reader) Reader { - return &multiReader{readers} + r := make([]Reader, len(readers)) + copy(r, readers) + return &multiReader{r} } type multiWriter struct { @@ -53,5 +55,7 @@ func (t *multiWriter) Write(p []byte) (n int, err error) { // MultiWriter creates a writer that duplicates its writes to all the // provided writers, similar to the Unix tee(1) command. func MultiWriter(writers ...Writer) Writer { - return &multiWriter{writers} + w := make([]Writer, len(writers)) + copy(w, writers) + return &multiWriter{w} } diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go index eb717f7bc21..56c6769a9eb 100644 --- a/libgo/go/io/multi_test.go +++ b/libgo/go/io/multi_test.go @@ -9,6 +9,7 @@ import ( "crypto/sha1" "fmt" . "io" + "io/ioutil" "strings" "testing" ) @@ -86,3 +87,29 @@ func TestMultiWriter(t *testing.T) { t.Errorf("expected %q; got %q", sourceString, sink.String()) } } + +// Test that MultiReader copies the input slice and is insulated from future modification. +func TestMultiReaderCopy(t *testing.T) { + slice := []Reader{strings.NewReader("hello world")} + r := MultiReader(slice...) + slice[0] = nil + data, err := ioutil.ReadAll(r) + if err != nil || string(data) != "hello world" { + t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world") + } +} + +// Test that MultiWriter copies the input slice and is insulated from future modification. +func TestMultiWriterCopy(t *testing.T) { + var buf bytes.Buffer + slice := []Writer{&buf} + w := MultiWriter(slice...) + slice[0] = nil + n, err := w.Write([]byte("hello world")) + if err != nil || n != 11 { + t.Errorf("Write(`hello world`) = %d, %v, want 11, nil", n, err) + } + if buf.String() != "hello world" { + t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world") + } +} diff --git a/libgo/go/log/syslog/syslog.go b/libgo/go/log/syslog/syslog.go index 0cbfa9011b8..5e095991626 100644 --- a/libgo/go/log/syslog/syslog.go +++ b/libgo/go/log/syslog/syslog.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows,!plan9 +// +build !windows,!nacl,!plan9 // Package syslog provides a simple interface to the system log // service. It can send messages to the syslog daemon using UNIX @@ -115,9 +115,10 @@ func New(priority Priority, tag string) (w *Writer, err error) { } // Dial establishes a connection to a log daemon by connecting to -// address raddr on the network net. Each write to the returned +// address raddr on the specified network. Each write to the returned // writer sends a log message with the given facility, severity and // tag. +// If network is empty, Dial will connect to the local syslog server. func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) { if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG { return nil, errors.New("log/syslog: invalid priority") diff --git a/libgo/go/log/syslog/syslog_test.go b/libgo/go/log/syslog/syslog_test.go index 760a5c7d1e9..24a460f6d9e 100644 --- a/libgo/go/log/syslog/syslog_test.go +++ b/libgo/go/log/syslog/syslog_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows,!plan9 +// +build !windows,!nacl,!plan9 package syslog diff --git a/libgo/go/log/syslog/syslog_unix.go b/libgo/go/log/syslog/syslog_unix.go index 28a294af963..f6d2f1b7a39 100644 --- a/libgo/go/log/syslog/syslog_unix.go +++ b/libgo/go/log/syslog/syslog_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows,!plan9 +// +build !windows,!nacl,!plan9 package syslog diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go index 4591590d409..269949d6160 100644 --- a/libgo/go/math/big/int.go +++ b/libgo/go/math/big/int.go @@ -576,21 +576,22 @@ func (x *Int) BitLen() int { } // Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z. -// If y <= 0, the result is 1; if m == nil or m == 0, z = x**y. +// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y. // See Knuth, volume 2, section 4.6.3. func (z *Int) Exp(x, y, m *Int) *Int { - if y.neg || len(y.abs) == 0 { - return z.SetInt64(1) + var yWords nat + if !y.neg { + yWords = y.abs } - // y > 0 + // y >= 0 var mWords nat if m != nil { mWords = m.abs // m.abs may be nil for m == 0 } - z.abs = z.abs.expNN(x.abs, y.abs, mWords) - z.neg = len(z.abs) > 0 && x.neg && y.abs[0]&1 == 1 // 0 has no sign + z.abs = z.abs.expNN(x.abs, yWords, mWords) + z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign return z } diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go index 3dd9c5b712b..299dc72fb1a 100644 --- a/libgo/go/math/big/int_test.go +++ b/libgo/go/math/big/int_test.go @@ -768,6 +768,19 @@ var expTests = []struct { x, y, m string out string }{ + // y <= 0 + {"0", "0", "", "1"}, + {"1", "0", "", "1"}, + {"-10", "0", "", "1"}, + {"1234", "-1", "", "1"}, + + // m == 1 + {"0", "0", "1", "0"}, + {"1", "0", "1", "0"}, + {"-10", "0", "1", "0"}, + {"1234", "-1", "1", "0"}, + + // misc {"5", "-7", "", "1"}, {"-5", "-7", "", "1"}, {"5", "0", "", "1"}, diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go index 6874900d0bd..16a87f5c537 100644 --- a/libgo/go/math/big/nat.go +++ b/libgo/go/math/big/nat.go @@ -1233,10 +1233,15 @@ func (z nat) expNN(x, y, m nat) nat { z = nil } + // x**y mod 1 == 0 + if len(m) == 1 && m[0] == 1 { + return z.setWord(0) + } + // m == 0 || m > 1 + + // x**0 == 1 if len(y) == 0 { - z = z.make(1) - z[0] = 1 - return z + return z.setWord(1) } // y > 0 diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go index 1d4dfe80d3d..a2ae53385c9 100644 --- a/libgo/go/math/big/nat_test.go +++ b/libgo/go/math/big/nat_test.go @@ -437,20 +437,11 @@ func BenchmarkStringPiParallel(b *testing.B) { if x.decimalString() != pi { panic("benchmark incorrect: conversion failed") } - n := runtime.GOMAXPROCS(0) - m := b.N / n // n*m <= b.N due to flooring, but the error is neglibible (n is not very large) - c := make(chan int, n) - for i := 0; i < n; i++ { - go func() { - for j := 0; j < m; j++ { - x.decimalString() - } - c <- 0 - }() - } - for i := 0; i < n; i++ { - <-c - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + x.decimalString() + } + }) } func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) } @@ -723,6 +714,12 @@ var expNNTests = []struct { x, y, m string out string }{ + {"0", "0", "0", "1"}, + {"0", "0", "1", "0"}, + {"1", "1", "1", "0"}, + {"2", "1", "1", "0"}, + {"2", "2", "1", "0"}, + {"10", "100000000000", "1", "0"}, {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"}, {"0x8000000000000000", "2", "6719", "4944"}, {"0x8000000000000000", "3", "6719", "5447"}, @@ -750,7 +747,7 @@ func TestExpNN(t *testing.T) { z := nat(nil).expNN(x, y, m) if z.cmp(out) != 0 { - t.Errorf("#%d got %v want %v", i, z, out) + t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString()) } } } diff --git a/libgo/go/math/big/rat.go b/libgo/go/math/big/rat.go index 3cdb1d807f5..f0973b3902f 100644 --- a/libgo/go/math/big/rat.go +++ b/libgo/go/math/big/rat.go @@ -47,7 +47,7 @@ func (z *Rat) SetFloat64(f float64) *Rat { shift := 52 - exp - // Optimisation (?): partially pre-normalise. + // Optimization (?): partially pre-normalise. for mantissa&1 == 0 && shift > 0 { mantissa >>= 1 shift-- @@ -477,7 +477,7 @@ func (z *Rat) SetString(s string) (*Rat, bool) { return z, true } -// String returns a string representation of z in the form "a/b" (even if b == 1). +// String returns a string representation of x in the form "a/b" (even if b == 1). func (x *Rat) String() string { s := "/1" if len(x.b.abs) != 0 { @@ -486,7 +486,7 @@ func (x *Rat) String() string { return x.a.String() + s } -// RatString returns a string representation of z in the form "a/b" if b != 1, +// RatString returns a string representation of x in the form "a/b" if b != 1, // and in the form "a" if b == 1. func (x *Rat) RatString() string { if x.IsInt() { @@ -495,7 +495,7 @@ func (x *Rat) RatString() string { return x.String() } -// FloatString returns a string representation of z in decimal form with prec +// FloatString returns a string representation of x in decimal form with prec // digits of precision after the decimal point and the last digit rounded. func (x *Rat) FloatString(prec int) string { if x.IsInt() { diff --git a/libgo/go/math/cmplx/cmath_test.go b/libgo/go/math/cmplx/cmath_test.go index 610ca8cebb2..f285646af7a 100644 --- a/libgo/go/math/cmplx/cmath_test.go +++ b/libgo/go/math/cmplx/cmath_test.go @@ -656,6 +656,19 @@ func TestPolar(t *testing.T) { } } func TestPow(t *testing.T) { + // Special cases for Pow(0, c). + var zero = complex(0, 0) + zeroPowers := [][2]complex128{ + {0, 1 + 0i}, + {1.5, 0 + 0i}, + {-1.5, complex(math.Inf(0), 0)}, + {-1.5 + 1.5i, Inf()}, + } + for _, zp := range zeroPowers { + if f := Pow(zero, zp[0]); f != zp[1] { + t.Errorf("Pow(%g, %g) = %g, want %g", zero, zp[0], f, zp[1]) + } + } var a = complex(3.0, 3.0) for i := 0; i < len(vc); i++ { if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) { diff --git a/libgo/go/math/cmplx/pow.go b/libgo/go/math/cmplx/pow.go index 4dbc58398b4..1630b879b88 100644 --- a/libgo/go/math/cmplx/pow.go +++ b/libgo/go/math/cmplx/pow.go @@ -43,7 +43,25 @@ import "math" // IEEE -10,+10 30000 9.4e-15 1.5e-15 // Pow returns x**y, the base-x exponential of y. +// For generalized compatibility with math.Pow: +// Pow(0, ±0) returns 1+0i +// Pow(0, c) for real(c)<0 returns Inf+0i if imag(c) is zero, otherwise Inf+Inf i. func Pow(x, y complex128) complex128 { + if x == 0 { // Guaranteed also true for x == -0. + r, i := real(y), imag(y) + switch { + case r == 0: + return 1 + case r < 0: + if i == 0 { + return complex(math.Inf(1), 0) + } + return Inf() + case r > 0: + return 0 + } + panic("not reached") + } modulus := Abs(x) if modulus == 0 { return complex(0, 0) diff --git a/libgo/go/math/cmplx/sqrt.go b/libgo/go/math/cmplx/sqrt.go index 179b5396abc..4ef6807addc 100644 --- a/libgo/go/math/cmplx/sqrt.go +++ b/libgo/go/math/cmplx/sqrt.go @@ -54,6 +54,7 @@ import "math" // IEEE -10,+10 1,000,000 2.9e-16 6.1e-17 // Sqrt returns the square root of x. +// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x). func Sqrt(x complex128) complex128 { if imag(x) == 0 { if real(x) == 0 { diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go index d3ea8401781..3ffb5c4e5c6 100644 --- a/libgo/go/math/rand/rand.go +++ b/libgo/go/math/rand/rand.go @@ -60,6 +60,9 @@ func (r *Rand) Int63n(n int64) int64 { if n <= 0 { panic("invalid argument to Int63n") } + if n&(n-1) == 0 { // n is power of two, can mask + return r.Int63() & (n - 1) + } max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) v := r.Int63() for v > max { @@ -74,6 +77,9 @@ func (r *Rand) Int31n(n int32) int32 { if n <= 0 { panic("invalid argument to Int31n") } + if n&(n-1) == 0 { // n is power of two, can mask + return r.Int31() & (n - 1) + } max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) v := r.Int31() for v > max { @@ -95,10 +101,46 @@ func (r *Rand) Intn(n int) int { } // Float64 returns, as a float64, a pseudo-random number in [0.0,1.0). -func (r *Rand) Float64() float64 { return float64(r.Int63n(1<<53)) / (1 << 53) } +func (r *Rand) Float64() float64 { + // A clearer, simpler implementation would be: + // return float64(r.Int63n(1<<53)) / (1<<53) + // However, Go 1 shipped with + // return float64(r.Int63()) / (1 << 63) + // and we want to preserve that value stream. + // + // There is one bug in the value stream: r.Int63() may be so close + // to 1<<63 that the division rounds up to 1.0, and we've guaranteed + // that the result is always less than 1.0. To fix that, we treat the + // range as cyclic and map 1 back to 0. This is justified by observing + // that while some of the values rounded down to 0, nothing was + // rounding up to 0, so 0 was underrepresented in the results. + // Mapping 1 back to zero restores some balance. + // (The balance is not perfect because the implementation + // returns denormalized numbers for very small r.Int63(), + // and those steal from what would normally be 0 results.) + // The remapping only happens 1/2⁵³ of the time, so most clients + // will not observe it anyway. + f := float64(r.Int63()) / (1 << 63) + if f == 1 { + f = 0 + } + return f +} // Float32 returns, as a float32, a pseudo-random number in [0.0,1.0). -func (r *Rand) Float32() float32 { return float32(r.Int31n(1<<24)) / (1 << 24) } +func (r *Rand) Float32() float32 { + // Same rationale as in Float64: we want to preserve the Go 1 value + // stream except we want to fix it not to return 1.0 + // There is a double rounding going on here, but the argument for + // mapping 1 to 0 still applies: 0 was underrepresented before, + // so mapping 1 to 0 doesn't cause too many 0s. + // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64). + f := float32(r.Float64()) + if f == 1 { + f = 0 + } + return f +} // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). func (r *Rand) Perm(n int) []int { diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go index c174c613f40..ab0dc49b411 100644 --- a/libgo/go/math/rand/rand_test.go +++ b/libgo/go/math/rand/rand_test.go @@ -376,6 +376,13 @@ func BenchmarkFloat32(b *testing.B) { } } +func BenchmarkFloat64(b *testing.B) { + r := New(NewSource(1)) + for n := b.N; n > 0; n-- { + r.Float64() + } +} + func BenchmarkPerm3(b *testing.B) { r := New(NewSource(1)) for n := b.N; n > 0; n-- { diff --git a/libgo/go/math/rand/regress_test.go b/libgo/go/math/rand/regress_test.go new file mode 100644 index 00000000000..2b012af893c --- /dev/null +++ b/libgo/go/math/rand/regress_test.go @@ -0,0 +1,355 @@ +// Copyright 2014 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. + +// Test that random number sequences generated by a specific seed +// do not change from version to version. +// +// Do NOT make changes to the golden outputs. If bugs need to be fixed +// in the underlying code, find ways to fix them that do not affect the +// outputs. + +package rand_test + +import ( + "flag" + "fmt" + . "math/rand" + "reflect" + "testing" +) + +var printgolden = flag.Bool("printgolden", false, "print golden results for regression test") + +func TestRegress(t *testing.T) { + var int32s = []int32{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1} + var int64s = []int64{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1, 1000000000000000000, 1 << 60, 1<<63 - 2, 1<<63 - 1} + var permSizes = []int{0, 1, 5, 8, 9, 10, 16} + r := New(NewSource(0)) + + rv := reflect.ValueOf(r) + n := rv.NumMethod() + p := 0 + if *printgolden { + fmt.Printf("var regressGolden = []interface{}{\n") + } + for i := 0; i < n; i++ { + m := rv.Type().Method(i) + mv := rv.Method(i) + mt := mv.Type() + if mt.NumOut() == 0 { + continue + } + if mt.NumOut() != 1 { + t.Fatalf("unexpected result count for r.%s", m.Name) + } + r.Seed(0) + for repeat := 0; repeat < 20; repeat++ { + var args []reflect.Value + var argstr string + if mt.NumIn() == 1 { + var x interface{} + switch mt.In(0).Kind() { + default: + t.Fatalf("unexpected argument type for r.%s", m.Name) + + case reflect.Int: + if m.Name == "Perm" { + x = permSizes[repeat%len(permSizes)] + break + } + big := int64s[repeat%len(int64s)] + if int64(int(big)) != big { + r.Int63n(big) // what would happen on 64-bit machine, to keep stream in sync + if *printgolden { + fmt.Printf("\tskipped, // must run printgolden on 64-bit machine\n") + } + p++ + continue + } + x = int(big) + + case reflect.Int32: + x = int32s[repeat%len(int32s)] + + case reflect.Int64: + x = int64s[repeat%len(int64s)] + } + argstr = fmt.Sprint(x) + args = append(args, reflect.ValueOf(x)) + } + out := mv.Call(args)[0].Interface() + if m.Name == "Int" || m.Name == "Intn" { + out = int64(out.(int)) + } + if *printgolden { + var val string + big := int64(1 << 60) + if int64(int(big)) != big && (m.Name == "Int" || m.Name == "Intn") { + // 32-bit machine cannot print 64-bit results + val = "truncated" + } else if reflect.TypeOf(out).Kind() == reflect.Slice { + val = fmt.Sprintf("%#v", out) + } else { + val = fmt.Sprintf("%T(%v)", out, out) + } + fmt.Printf("\t%s, // %s(%s)\n", val, m.Name, argstr) + } else { + want := regressGolden[p] + if m.Name == "Int" { + want = int64(int(uint(want.(int64)) << 1 >> 1)) + } + if !reflect.DeepEqual(out, want) { + t.Errorf("r.%s(%s) = %v, want %v", m.Name, argstr, out, want) + } + } + p++ + } + } + if *printgolden { + fmt.Printf("}\n") + } +} + +var regressGolden = []interface{}{ + float64(4.668112973579268), // ExpFloat64() + float64(0.1601593871172866), // ExpFloat64() + float64(3.0465834105636), // ExpFloat64() + float64(0.06385839451671879), // ExpFloat64() + float64(1.8578917487258961), // ExpFloat64() + float64(0.784676123472182), // ExpFloat64() + float64(0.11225477361256932), // ExpFloat64() + float64(0.20173283329802255), // ExpFloat64() + float64(0.3468619496201105), // ExpFloat64() + float64(0.35601103454384536), // ExpFloat64() + float64(0.888376329507869), // ExpFloat64() + float64(1.4081362450365698), // ExpFloat64() + float64(1.0077753823151994), // ExpFloat64() + float64(0.23594100766227588), // ExpFloat64() + float64(2.777245612300007), // ExpFloat64() + float64(0.5202997830662377), // ExpFloat64() + float64(1.2842705247770294), // ExpFloat64() + float64(0.030307408362776206), // ExpFloat64() + float64(2.204156824853721), // ExpFloat64() + float64(2.09891923895058), // ExpFloat64() + float32(0.94519615), // Float32() + float32(0.24496509), // Float32() + float32(0.65595627), // Float32() + float32(0.05434384), // Float32() + float32(0.3675872), // Float32() + float32(0.28948045), // Float32() + float32(0.1924386), // Float32() + float32(0.65533215), // Float32() + float32(0.8971697), // Float32() + float32(0.16735445), // Float32() + float32(0.28858566), // Float32() + float32(0.9026048), // Float32() + float32(0.84978026), // Float32() + float32(0.2730468), // Float32() + float32(0.6090802), // Float32() + float32(0.253656), // Float32() + float32(0.7746542), // Float32() + float32(0.017480763), // Float32() + float32(0.78707397), // Float32() + float32(0.7993937), // Float32() + float64(0.9451961492941164), // Float64() + float64(0.24496508529377975), // Float64() + float64(0.6559562651954052), // Float64() + float64(0.05434383959970039), // Float64() + float64(0.36758720663245853), // Float64() + float64(0.2894804331565928), // Float64() + float64(0.19243860967493215), // Float64() + float64(0.6553321508148324), // Float64() + float64(0.897169713149801), // Float64() + float64(0.16735444255905835), // Float64() + float64(0.2885856518054551), // Float64() + float64(0.9026048462705047), // Float64() + float64(0.8497802817628735), // Float64() + float64(0.2730468047134829), // Float64() + float64(0.6090801919903561), // Float64() + float64(0.25365600644283687), // Float64() + float64(0.7746542391859803), // Float64() + float64(0.017480762156647272), // Float64() + float64(0.7870739563039942), // Float64() + float64(0.7993936979594545), // Float64() + int64(8717895732742165505), // Int() + int64(2259404117704393152), // Int() + int64(6050128673802995827), // Int() + int64(501233450539197794), // Int() + int64(3390393562759376202), // Int() + int64(2669985732393126063), // Int() + int64(1774932891286980153), // Int() + int64(6044372234677422456), // Int() + int64(8274930044578894929), // Int() + int64(1543572285742637646), // Int() + int64(2661732831099943416), // Int() + int64(8325060299420976708), // Int() + int64(7837839688282259259), // Int() + int64(2518412263346885298), // Int() + int64(5617773211005988520), // Int() + int64(2339563716805116249), // Int() + int64(7144924247938981575), // Int() + int64(161231572858529631), // Int() + int64(7259475919510918339), // Int() + int64(7373105480197164748), // Int() + int32(2029793274), // Int31() + int32(526058514), // Int31() + int32(1408655353), // Int31() + int32(116702506), // Int31() + int32(789387515), // Int31() + int32(621654496), // Int31() + int32(413258767), // Int31() + int32(1407315077), // Int31() + int32(1926657288), // Int31() + int32(359390928), // Int31() + int32(619732968), // Int31() + int32(1938329147), // Int31() + int32(1824889259), // Int31() + int32(586363548), // Int31() + int32(1307989752), // Int31() + int32(544722126), // Int31() + int32(1663557311), // Int31() + int32(37539650), // Int31() + int32(1690228450), // Int31() + int32(1716684894), // Int31() + int32(0), // Int31n(1) + int32(4), // Int31n(10) + int32(25), // Int31n(32) + int32(310570), // Int31n(1048576) + int32(857611), // Int31n(1048577) + int32(621654496), // Int31n(1000000000) + int32(413258767), // Int31n(1073741824) + int32(1407315077), // Int31n(2147483646) + int32(1926657288), // Int31n(2147483647) + int32(0), // Int31n(1) + int32(8), // Int31n(10) + int32(27), // Int31n(32) + int32(367019), // Int31n(1048576) + int32(209005), // Int31n(1048577) + int32(307989752), // Int31n(1000000000) + int32(544722126), // Int31n(1073741824) + int32(1663557311), // Int31n(2147483646) + int32(37539650), // Int31n(2147483647) + int32(0), // Int31n(1) + int32(4), // Int31n(10) + int64(8717895732742165505), // Int63() + int64(2259404117704393152), // Int63() + int64(6050128673802995827), // Int63() + int64(501233450539197794), // Int63() + int64(3390393562759376202), // Int63() + int64(2669985732393126063), // Int63() + int64(1774932891286980153), // Int63() + int64(6044372234677422456), // Int63() + int64(8274930044578894929), // Int63() + int64(1543572285742637646), // Int63() + int64(2661732831099943416), // Int63() + int64(8325060299420976708), // Int63() + int64(7837839688282259259), // Int63() + int64(2518412263346885298), // Int63() + int64(5617773211005988520), // Int63() + int64(2339563716805116249), // Int63() + int64(7144924247938981575), // Int63() + int64(161231572858529631), // Int63() + int64(7259475919510918339), // Int63() + int64(7373105480197164748), // Int63() + int64(0), // Int63n(1) + int64(2), // Int63n(10) + int64(19), // Int63n(32) + int64(959842), // Int63n(1048576) + int64(688912), // Int63n(1048577) + int64(393126063), // Int63n(1000000000) + int64(89212473), // Int63n(1073741824) + int64(834026388), // Int63n(2147483646) + int64(1577188963), // Int63n(2147483647) + int64(543572285742637646), // Int63n(1000000000000000000) + int64(355889821886249464), // Int63n(1152921504606846976) + int64(8325060299420976708), // Int63n(9223372036854775806) + int64(7837839688282259259), // Int63n(9223372036854775807) + int64(0), // Int63n(1) + int64(0), // Int63n(10) + int64(25), // Int63n(32) + int64(679623), // Int63n(1048576) + int64(882178), // Int63n(1048577) + int64(510918339), // Int63n(1000000000) + int64(782454476), // Int63n(1073741824) + int64(0), // Intn(1) + int64(4), // Intn(10) + int64(25), // Intn(32) + int64(310570), // Intn(1048576) + int64(857611), // Intn(1048577) + int64(621654496), // Intn(1000000000) + int64(413258767), // Intn(1073741824) + int64(1407315077), // Intn(2147483646) + int64(1926657288), // Intn(2147483647) + int64(543572285742637646), // Intn(1000000000000000000) + int64(355889821886249464), // Intn(1152921504606846976) + int64(8325060299420976708), // Intn(9223372036854775806) + int64(7837839688282259259), // Intn(9223372036854775807) + int64(0), // Intn(1) + int64(2), // Intn(10) + int64(14), // Intn(32) + int64(515775), // Intn(1048576) + int64(839455), // Intn(1048577) + int64(690228450), // Intn(1000000000) + int64(642943070), // Intn(1073741824) + float64(-0.28158587086436215), // NormFloat64() + float64(0.570933095808067), // NormFloat64() + float64(-1.6920196326157044), // NormFloat64() + float64(0.1996229111693099), // NormFloat64() + float64(1.9195199291234621), // NormFloat64() + float64(0.8954838794918353), // NormFloat64() + float64(0.41457072128813166), // NormFloat64() + float64(-0.48700161491544713), // NormFloat64() + float64(-0.1684059662402393), // NormFloat64() + float64(0.37056410998929545), // NormFloat64() + float64(1.0156889027029008), // NormFloat64() + float64(-0.5174422210625114), // NormFloat64() + float64(-0.5565834214413804), // NormFloat64() + float64(0.778320596648391), // NormFloat64() + float64(-1.8970718197702225), // NormFloat64() + float64(0.5229525761688676), // NormFloat64() + float64(-1.5515595563231523), // NormFloat64() + float64(0.0182029289376123), // NormFloat64() + float64(-0.6820951356608795), // NormFloat64() + float64(-0.5987943422687668), // NormFloat64() + []int{}, // Perm(0) + []int{0}, // Perm(1) + []int{0, 4, 1, 3, 2}, // Perm(5) + []int{3, 1, 0, 4, 7, 5, 2, 6}, // Perm(8) + []int{5, 0, 3, 6, 7, 4, 2, 1, 8}, // Perm(9) + []int{4, 5, 0, 2, 6, 9, 3, 1, 8, 7}, // Perm(10) + []int{14, 2, 0, 8, 3, 5, 13, 12, 1, 4, 6, 7, 11, 9, 15, 10}, // Perm(16) + []int{}, // Perm(0) + []int{0}, // Perm(1) + []int{3, 0, 1, 2, 4}, // Perm(5) + []int{5, 1, 2, 0, 4, 7, 3, 6}, // Perm(8) + []int{4, 0, 6, 8, 1, 5, 2, 7, 3}, // Perm(9) + []int{8, 6, 1, 7, 5, 4, 3, 2, 9, 0}, // Perm(10) + []int{0, 3, 13, 2, 15, 4, 10, 1, 8, 14, 7, 6, 12, 9, 5, 11}, // Perm(16) + []int{}, // Perm(0) + []int{0}, // Perm(1) + []int{0, 4, 2, 1, 3}, // Perm(5) + []int{2, 1, 7, 0, 6, 3, 4, 5}, // Perm(8) + []int{8, 7, 5, 3, 4, 6, 0, 1, 2}, // Perm(9) + []int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10) + uint32(4059586549), // Uint32() + uint32(1052117029), // Uint32() + uint32(2817310706), // Uint32() + uint32(233405013), // Uint32() + uint32(1578775030), // Uint32() + uint32(1243308993), // Uint32() + uint32(826517535), // Uint32() + uint32(2814630155), // Uint32() + uint32(3853314576), // Uint32() + uint32(718781857), // Uint32() + uint32(1239465936), // Uint32() + uint32(3876658295), // Uint32() + uint32(3649778518), // Uint32() + uint32(1172727096), // Uint32() + uint32(2615979505), // Uint32() + uint32(1089444252), // Uint32() + uint32(3327114623), // Uint32() + uint32(75079301), // Uint32() + uint32(3380456901), // Uint32() + uint32(3433369789), // Uint32() +} diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go index 608f759da8f..ad63f9bb98e 100644 --- a/libgo/go/mime/mediatype.go +++ b/libgo/go/mime/mediatype.go @@ -8,6 +8,7 @@ import ( "bytes" "errors" "fmt" + "sort" "strings" "unicode" ) @@ -31,7 +32,14 @@ func FormatMediaType(t string, param map[string]string) string { b.WriteByte('/') b.WriteString(strings.ToLower(sub)) - for attribute, value := range param { + attrs := make([]string, 0, len(param)) + for a := range param { + attrs = append(attrs, a) + } + sort.Strings(attrs) + + for _, attribute := range attrs { + value := param[attribute] b.WriteByte(';') b.WriteByte(' ') if !isToken(attribute) { diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go index 29511445bcf..026bfa4d734 100644 --- a/libgo/go/mime/mediatype_test.go +++ b/libgo/go/mime/mediatype_test.go @@ -293,6 +293,7 @@ var formatTests = []formatTest{ {"foo/BAR", map[string]string{"": "empty attribute"}, ""}, {"foo/BAR", map[string]string{"bad attribute": "baz"}, ""}, {"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, ""}, + {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"}, } func TestFormatMediaType(t *testing.T) { diff --git a/libgo/go/mime/multipart/multipart.go b/libgo/go/mime/multipart/multipart.go index 2b4f5b433ec..7382efab967 100644 --- a/libgo/go/mime/multipart/multipart.go +++ b/libgo/go/mime/multipart/multipart.go @@ -81,12 +81,16 @@ func (p *Part) parseContentDisposition() { } } -// NewReader creates a new multipart Reader reading from reader using the +// NewReader creates a new multipart Reader reading from r using the // given MIME boundary. -func NewReader(reader io.Reader, boundary string) *Reader { +// +// The boundary is usually obtained from the "boundary" parameter of +// the message's "Content-Type" header. Use mime.ParseMediaType to +// parse such headers. +func NewReader(r io.Reader, boundary string) *Reader { b := []byte("\r\n--" + boundary + "--") return &Reader{ - bufReader: bufio.NewReader(reader), + bufReader: bufio.NewReader(r), nl: b[:2], nlDashBoundary: b[:len(b)-2], diff --git a/libgo/go/mime/multipart/quotedprintable_test.go b/libgo/go/mime/multipart/quotedprintable_test.go index 8a95f7f037b..c4de3eb7566 100644 --- a/libgo/go/mime/multipart/quotedprintable_test.go +++ b/libgo/go/mime/multipart/quotedprintable_test.go @@ -131,7 +131,7 @@ func TestQPExhaustive(t *testing.T) { return } if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") { - // bunch of cases; since whitespace at the end of of a line before \n is removed. + // bunch of cases; since whitespace at the end of a line before \n is removed. return } } diff --git a/libgo/go/mime/type_unix.go b/libgo/go/mime/type_unix.go index d949ba3f3e5..1d394315a49 100644 --- a/libgo/go/mime/type_unix.go +++ b/libgo/go/mime/type_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package mime diff --git a/libgo/go/net/cgo_bsd.go b/libgo/go/net/cgo_bsd.go index 3852fc22987..ce46f2e8c3a 100644 --- a/libgo/go/net/cgo_bsd.go +++ b/libgo/go/net/cgo_bsd.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build !netgo -// +build darwin dragonfly freebsd +// +build darwin dragonfly freebsd solaris package net diff --git a/libgo/go/net/conn_test.go b/libgo/go/net/conn_test.go index 7250dcb85ad..37bb4e2c071 100644 --- a/libgo/go/net/conn_test.go +++ b/libgo/go/net/conn_test.go @@ -16,11 +16,11 @@ import ( var connTests = []struct { net string - addr func() string + addr string }{ - {"tcp", func() string { return "127.0.0.1:0" }}, - {"unix", testUnixAddr}, - {"unixpacket", testUnixAddr}, + {"tcp", "127.0.0.1:0"}, + {"unix", testUnixAddr()}, + {"unixpacket", testUnixAddr()}, } // someTimeout is used just to test that net.Conn implementations @@ -31,18 +31,21 @@ const someTimeout = 10 * time.Second func TestConnAndListener(t *testing.T) { for _, tt := range connTests { switch tt.net { - case "unix", "unixpacket": + case "unix": switch runtime.GOOS { - case "plan9", "windows": + case "nacl", "plan9", "windows": continue } - if tt.net == "unixpacket" && runtime.GOOS != "linux" { + case "unixpacket": + switch runtime.GOOS { + case "darwin", "nacl", "openbsd", "plan9", "windows": + continue + case "freebsd": // FreeBSD 8 doesn't support unixpacket continue } } - addr := tt.addr() - ln, err := Listen(tt.net, addr) + ln, err := Listen(tt.net, tt.addr) if err != nil { t.Fatalf("Listen failed: %v", err) } @@ -52,7 +55,7 @@ func TestConnAndListener(t *testing.T) { case "unix", "unixpacket": os.Remove(addr) } - }(ln, tt.net, addr) + }(ln, tt.net, tt.addr) if ln.Addr().Network() != tt.net { t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net) } diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go index 70b66e70d15..93569c253cd 100644 --- a/libgo/go/net/dial.go +++ b/libgo/go/net/dial.go @@ -44,6 +44,12 @@ type Dialer struct { // destination is a host name that has multiple address family // DNS records. DualStack bool + + // KeepAlive specifies the keep-alive period for an active + // network connection. + // If zero, keep-alives are not enabled. Network protocols + // that do not support keep-alives ignore this field. + KeepAlive time.Duration } // Return either now+Timeout or Deadline, whichever comes first. @@ -162,9 +168,19 @@ func (d *Dialer) Dial(network, address string) (Conn, error) { return dialMulti(network, address, d.LocalAddr, ras, deadline) } } - return dial(network, ra.toAddr(), dialer, d.deadline()) + c, err := dial(network, ra.toAddr(), dialer, d.deadline()) + if d.KeepAlive > 0 && err == nil { + if tc, ok := c.(*TCPConn); ok { + tc.SetKeepAlive(true) + tc.SetKeepAlivePeriod(d.KeepAlive) + testHookSetKeepAlive() + } + } + return c, err } +var testHookSetKeepAlive = func() {} // changed by dial_test.go + // dialMulti attempts to establish connections to each destination of // the list of addresses. It will return the first established // connection and close the other connections. Otherwise it returns diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go index 08a0567ca76..f9260fd281b 100644 --- a/libgo/go/net/dial_test.go +++ b/libgo/go/net/dial_test.go @@ -425,60 +425,6 @@ func numFD() int { panic("numFDs not implemented on " + runtime.GOOS) } -// Assert that a failed Dial attempt does not leak -// runtime.PollDesc structures -func TestDialFailPDLeak(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode") - } - if runtime.GOOS == "windows" && runtime.GOARCH == "386" { - // Just skip the test because it takes too long. - t.Skipf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH) - } - - maxprocs := runtime.GOMAXPROCS(0) - loops := 10 + maxprocs - // 500 is enough to turn over the chunk of pollcache. - // See allocPollDesc in runtime/netpoll.goc. - const count = 500 - var old runtime.MemStats // used by sysdelta - runtime.ReadMemStats(&old) - sysdelta := func() uint64 { - var new runtime.MemStats - runtime.ReadMemStats(&new) - delta := old.Sys - new.Sys - old = new - return delta - } - d := &Dialer{Timeout: time.Nanosecond} // don't bother TCP with handshaking - failcount := 0 - for i := 0; i < loops; i++ { - var wg sync.WaitGroup - for i := 0; i < count; i++ { - wg.Add(1) - go func() { - defer wg.Done() - if c, err := d.Dial("tcp", "127.0.0.1:1"); err == nil { - t.Error("dial should not succeed") - c.Close() - } - }() - } - wg.Wait() - if t.Failed() { - t.FailNow() - } - if delta := sysdelta(); delta > 0 { - failcount++ - } - // there are always some allocations on the first loop - if failcount > maxprocs+2 { - t.Error("detected possible memory leak in runtime") - t.FailNow() - } - } -} - func TestDialer(t *testing.T) { ln, err := Listen("tcp4", "127.0.0.1:0") if err != nil { @@ -555,3 +501,36 @@ func TestDialDualStackLocalhost(t *testing.T) { } } } + +func TestDialerKeepAlive(t *testing.T) { + ln := newLocalListener(t) + defer ln.Close() + defer func() { + testHookSetKeepAlive = func() {} + }() + go func() { + for { + c, err := ln.Accept() + if err != nil { + return + } + c.Close() + } + }() + for _, keepAlive := range []bool{false, true} { + got := false + testHookSetKeepAlive = func() { got = true } + var d Dialer + if keepAlive { + d.KeepAlive = 30 * time.Second + } + c, err := d.Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + c.Close() + if got != keepAlive { + t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got) + } + } +} diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go index 01db4372945..9bffa11f916 100644 --- a/libgo/go/net/dnsclient.go +++ b/libgo/go/net/dnsclient.go @@ -191,10 +191,10 @@ func (addrs byPriorityWeight) shuffleByWeight() { } for sum > 0 && len(addrs) > 1 { s := 0 - n := rand.Intn(sum + 1) + n := rand.Intn(sum) for i := range addrs { s += int(addrs[i].Weight) - if s >= n { + if s > n { if i > 0 { t := addrs[i] copy(addrs[1:i+1], addrs[0:i]) diff --git a/libgo/go/net/dnsclient_test.go b/libgo/go/net/dnsclient_test.go new file mode 100644 index 00000000000..435eb35506e --- /dev/null +++ b/libgo/go/net/dnsclient_test.go @@ -0,0 +1,69 @@ +// Copyright 2014 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. + +package net + +import ( + "math/rand" + "testing" +) + +func checkDistribution(t *testing.T, data []*SRV, margin float64) { + sum := 0 + for _, srv := range data { + sum += int(srv.Weight) + } + + results := make(map[string]int) + + count := 1000 + for j := 0; j < count; j++ { + d := make([]*SRV, len(data)) + copy(d, data) + byPriorityWeight(d).shuffleByWeight() + key := d[0].Target + results[key] = results[key] + 1 + } + + actual := results[data[0].Target] + expected := float64(count) * float64(data[0].Weight) / float64(sum) + diff := float64(actual) - expected + t.Logf("actual: %v diff: %v e: %v m: %v", actual, diff, expected, margin) + if diff < 0 { + diff = -diff + } + if diff > (expected * margin) { + t.Errorf("missed target weight: expected %v, %v", expected, actual) + } +} + +func testUniformity(t *testing.T, size int, margin float64) { + rand.Seed(1) + data := make([]*SRV, size) + for i := 0; i < size; i++ { + data[i] = &SRV{Target: string('a' + i), Weight: 1} + } + checkDistribution(t, data, margin) +} + +func TestUniformity(t *testing.T) { + testUniformity(t, 2, 0.05) + testUniformity(t, 3, 0.10) + testUniformity(t, 10, 0.20) + testWeighting(t, 0.05) +} + +func testWeighting(t *testing.T, margin float64) { + rand.Seed(1) + data := []*SRV{ + {Target: "a", Weight: 60}, + {Target: "b", Weight: 30}, + {Target: "c", Weight: 10}, + } + checkDistribution(t, data, margin) +} + +func TestWeighting(t *testing.T) { + testWeighting(t, 0.05) +} diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index a30c9a73d7e..3713efd0e3c 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -2,13 +2,12 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris // DNS client: see RFC 1035. // Has to be linked into package net for Dial. // TODO(rsc): -// Check periodically whether /etc/resolv.conf has changed. // Could potentially handle many outstanding lookups faster. // Could have a small cache. // Random UDP source port (net.Dial should do that for us). @@ -19,6 +18,7 @@ package net import ( "io" "math/rand" + "os" "sync" "time" ) @@ -156,33 +156,90 @@ func convertRR_AAAA(records []dnsRR) []IP { return addrs } -var cfg *dnsConfig -var dnserr error +var cfg struct { + ch chan struct{} + mu sync.RWMutex // protects dnsConfig and dnserr + dnsConfig *dnsConfig + dnserr error +} +var onceLoadConfig sync.Once // Assume dns config file is /etc/resolv.conf here -func loadConfig() { cfg, dnserr = dnsReadConfig("/etc/resolv.conf") } +func loadDefaultConfig() { + loadConfig("/etc/resolv.conf", 5*time.Second, nil) +} -var onceLoadConfig sync.Once +func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) { + var mtime time.Time + cfg.ch = make(chan struct{}, 1) + if fi, err := os.Stat(resolvConfPath); err != nil { + cfg.dnserr = err + } else { + mtime = fi.ModTime() + cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath) + } + go func() { + for { + time.Sleep(reloadTime) + select { + case qresp := <-quit: + qresp <- struct{}{} + return + case <-cfg.ch: + } + + // In case of error, we keep the previous config + fi, err := os.Stat(resolvConfPath) + if err != nil { + continue + } + // If the resolv.conf mtime didn't change, do not reload + m := fi.ModTime() + if m.Equal(mtime) { + continue + } + mtime = m + // In case of error, we keep the previous config + ncfg, err := dnsReadConfig(resolvConfPath) + if err != nil || len(ncfg.servers) == 0 { + continue + } + cfg.mu.Lock() + cfg.dnsConfig = ncfg + cfg.dnserr = nil + cfg.mu.Unlock() + } + }() +} func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) { if !isDomainName(name) { return name, nil, &DNSError{Err: "invalid domain name", Name: name} } - onceLoadConfig.Do(loadConfig) - if dnserr != nil || cfg == nil { - err = dnserr + onceLoadConfig.Do(loadDefaultConfig) + + select { + case cfg.ch <- struct{}{}: + default: + } + + cfg.mu.RLock() + defer cfg.mu.RUnlock() + + if cfg.dnserr != nil || cfg.dnsConfig == nil { + err = cfg.dnserr return } // If name is rooted (trailing dot) or has enough dots, // try it by itself first. rooted := len(name) > 0 && name[len(name)-1] == '.' - if rooted || count(name, '.') >= cfg.ndots { + if rooted || count(name, '.') >= cfg.dnsConfig.ndots { rname := name if !rooted { rname += "." } // Can try as ordinary name. - cname, addrs, err = tryOneName(cfg, rname, qtype) + cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype) if err == nil { return } @@ -192,12 +249,12 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) } // Otherwise, try suffixes. - for i := 0; i < len(cfg.search); i++ { - rname := name + "." + cfg.search[i] + for i := 0; i < len(cfg.dnsConfig.search); i++ { + rname := name + "." + cfg.dnsConfig.search[i] if rname[len(rname)-1] != '.' { rname += "." } - cname, addrs, err = tryOneName(cfg, rname, qtype) + cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype) if err == nil { return } @@ -208,7 +265,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) if !rooted { rname += "." } - cname, addrs, err = tryOneName(cfg, rname, qtype) + cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype) if err == nil { return } @@ -233,11 +290,6 @@ func goLookupHost(name string) (addrs []string, err error) { if len(addrs) > 0 { return } - onceLoadConfig.Do(loadConfig) - if dnserr != nil || cfg == nil { - err = dnserr - return - } ips, err := goLookupIP(name) if err != nil { return @@ -268,11 +320,6 @@ func goLookupIP(name string) (addrs []IP, err error) { return } } - onceLoadConfig.Do(loadConfig) - if dnserr != nil || cfg == nil { - err = dnserr - return - } var records []dnsRR var cname string var err4, err6 error @@ -308,11 +355,6 @@ func goLookupIP(name string) (addrs []IP, err error) { // depending on our lookup code, so that Go and C get the same // answers. func goLookupCNAME(name string) (cname string, err error) { - onceLoadConfig.Do(loadConfig) - if dnserr != nil || cfg == nil { - err = dnserr - return - } _, rr, err := lookup(name, dnsTypeCNAME) if err != nil { return diff --git a/libgo/go/net/dnsclient_unix_test.go b/libgo/go/net/dnsclient_unix_test.go index 47dcb563bc5..2350142d610 100644 --- a/libgo/go/net/dnsclient_unix_test.go +++ b/libgo/go/net/dnsclient_unix_test.go @@ -2,12 +2,18 @@ // 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 +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package net import ( + "io" + "io/ioutil" + "os" + "path" + "reflect" "testing" + "time" ) func TestTCPLookup(t *testing.T) { @@ -25,3 +31,129 @@ func TestTCPLookup(t *testing.T) { t.Fatalf("exchange failed: %v", err) } } + +type resolvConfTest struct { + *testing.T + dir string + path string + started bool + quitc chan chan struct{} +} + +func newResolvConfTest(t *testing.T) *resolvConfTest { + dir, err := ioutil.TempDir("", "resolvConfTest") + if err != nil { + t.Fatalf("could not create temp dir: %v", err) + } + + // Disable the default loadConfig + onceLoadConfig.Do(func() {}) + + r := &resolvConfTest{ + T: t, + dir: dir, + path: path.Join(dir, "resolv.conf"), + quitc: make(chan chan struct{}), + } + + return r +} + +func (r *resolvConfTest) Start() { + loadConfig(r.path, 100*time.Millisecond, r.quitc) + r.started = true +} + +func (r *resolvConfTest) SetConf(s string) { + // Make sure the file mtime will be different once we're done here, + // even on systems with coarse (1s) mtime resolution. + time.Sleep(time.Second) + + f, err := os.OpenFile(r.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) + if err != nil { + r.Fatalf("failed to create temp file %s: %v", r.path, err) + } + if _, err := io.WriteString(f, s); err != nil { + f.Close() + r.Fatalf("failed to write temp file: %v", err) + } + f.Close() + + if r.started { + cfg.ch <- struct{}{} // fill buffer + cfg.ch <- struct{}{} // wait for reload to begin + cfg.ch <- struct{}{} // wait for reload to complete + } +} + +func (r *resolvConfTest) WantServers(want []string) { + cfg.mu.RLock() + defer cfg.mu.RUnlock() + if got := cfg.dnsConfig.servers; !reflect.DeepEqual(got, want) { + r.Fatalf("Unexpected dns server loaded, got %v want %v", got, want) + } +} + +func (r *resolvConfTest) Close() { + resp := make(chan struct{}) + r.quitc <- resp + <-resp + if err := os.RemoveAll(r.dir); err != nil { + r.Logf("failed to remove temp dir %s: %v", r.dir, err) + } +} + +func TestReloadResolvConfFail(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skip("skipping test to avoid external network") + } + + r := newResolvConfTest(t) + defer r.Close() + + // resolv.conf.tmp does not exist yet + r.Start() + if _, err := goLookupIP("golang.org"); err == nil { + t.Fatal("goLookupIP(missing) succeeded") + } + + r.SetConf("nameserver 8.8.8.8") + if _, err := goLookupIP("golang.org"); err != nil { + t.Fatalf("goLookupIP(missing; good) failed: %v", err) + } + + // Using a bad resolv.conf while we had a good + // one before should not update the config + r.SetConf("") + if _, err := goLookupIP("golang.org"); err != nil { + t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err) + } +} + +func TestReloadResolvConfChange(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skip("skipping test to avoid external network") + } + + r := newResolvConfTest(t) + defer r.Close() + + r.SetConf("nameserver 8.8.8.8") + r.Start() + + if _, err := goLookupIP("golang.org"); err != nil { + t.Fatalf("goLookupIP(good) failed: %v", err) + } + r.WantServers([]string{"[8.8.8.8]"}) + + // Using a bad resolv.conf when we had a good one + // before should not update the config + r.SetConf("") + if _, err := goLookupIP("golang.org"); err != nil { + t.Fatalf("goLookupIP(good; bad) failed: %v", err) + } + + // A new good config should get picked up + r.SetConf("nameserver 8.8.4.4") + r.WantServers([]string{"[8.8.4.4]"}) +} diff --git a/libgo/go/net/dnsconfig_unix.go b/libgo/go/net/dnsconfig_unix.go index 7856ebc80de..af288253e09 100644 --- a/libgo/go/net/dnsconfig_unix.go +++ b/libgo/go/net/dnsconfig_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris // Read system DNS config from /etc/resolv.conf diff --git a/libgo/go/net/dnsconfig_unix_test.go b/libgo/go/net/dnsconfig_unix_test.go index 697c69f9959..37ed4931dbe 100644 --- a/libgo/go/net/dnsconfig_unix_test.go +++ b/libgo/go/net/dnsconfig_unix_test.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/libgo/go/net/fd_mutex_test.go b/libgo/go/net/fd_mutex_test.go index 8383084b7a2..c34ec59b996 100644 --- a/libgo/go/net/fd_mutex_test.go +++ b/libgo/go/net/fd_mutex_test.go @@ -63,7 +63,8 @@ func TestMutexCloseUnblock(t *testing.T) { for i := 0; i < 4; i++ { go func() { if mu.RWLock(true) { - t.Fatal("broken") + t.Error("broken") + return } c <- true }() @@ -138,36 +139,44 @@ func TestMutexStress(t *testing.T) { switch r.Intn(3) { case 0: if !mu.Incref() { - t.Fatal("broken") + t.Error("broken") + return } if mu.Decref() { - t.Fatal("broken") + t.Error("broken") + return } case 1: if !mu.RWLock(true) { - t.Fatal("broken") + t.Error("broken") + return } // Ensure that it provides mutual exclusion for readers. if readState[0] != readState[1] { - t.Fatal("broken") + t.Error("broken") + return } readState[0]++ readState[1]++ if mu.RWUnlock(true) { - t.Fatal("broken") + t.Error("broken") + return } case 2: if !mu.RWLock(false) { - t.Fatal("broken") + t.Error("broken") + return } // Ensure that it provides mutual exclusion for writers. if writeState[0] != writeState[1] { - t.Fatal("broken") + t.Error("broken") + return } writeState[0]++ writeState[1]++ if mu.RWUnlock(false) { - t.Fatal("broken") + t.Error("broken") + return } } } diff --git a/libgo/go/net/fd_plan9.go b/libgo/go/net/fd_plan9.go index 4309a87c3a4..5fe8effc295 100644 --- a/libgo/go/net/fd_plan9.go +++ b/libgo/go/net/fd_plan9.go @@ -150,14 +150,14 @@ func (fd *netFD) Write(b []byte) (n int, err error) { return fd.data.Write(b) } -func (fd *netFD) CloseRead() error { +func (fd *netFD) closeRead() error { if !fd.ok() { return syscall.EINVAL } return syscall.EPLAN9 } -func (fd *netFD) CloseWrite() error { +func (fd *netFD) closeWrite() error { if !fd.ok() { return syscall.EINVAL } diff --git a/libgo/go/net/fd_poll_nacl.go b/libgo/go/net/fd_poll_nacl.go new file mode 100644 index 00000000000..a3701f87648 --- /dev/null +++ b/libgo/go/net/fd_poll_nacl.go @@ -0,0 +1,94 @@ +// Copyright 2013 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. + +package net + +import ( + "syscall" + "time" +) + +type pollDesc struct { + fd *netFD + closing bool +} + +func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil } + +func (pd *pollDesc) Close() {} + +func (pd *pollDesc) Lock() {} + +func (pd *pollDesc) Unlock() {} + +func (pd *pollDesc) Wakeup() {} + +func (pd *pollDesc) Evict() bool { + pd.closing = true + if pd.fd != nil { + syscall.StopIO(pd.fd.sysfd) + } + return false +} + +func (pd *pollDesc) Prepare(mode int) error { + if pd.closing { + return errClosing + } + return nil +} + +func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') } + +func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') } + +func (pd *pollDesc) Wait(mode int) error { + if pd.closing { + return errClosing + } + return errTimeout +} + +func (pd *pollDesc) WaitRead() error { return pd.Wait('r') } + +func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') } + +func (pd *pollDesc) WaitCanceled(mode int) {} + +func (pd *pollDesc) WaitCanceledRead() {} + +func (pd *pollDesc) WaitCanceledWrite() {} + +func (fd *netFD) setDeadline(t time.Time) error { + return setDeadlineImpl(fd, t, 'r'+'w') +} + +func (fd *netFD) setReadDeadline(t time.Time) error { + return setDeadlineImpl(fd, t, 'r') +} + +func (fd *netFD) setWriteDeadline(t time.Time) error { + return setDeadlineImpl(fd, t, 'w') +} + +func setDeadlineImpl(fd *netFD, t time.Time, mode int) error { + d := t.UnixNano() + if t.IsZero() { + d = 0 + } + if err := fd.incref(); err != nil { + return err + } + switch mode { + case 'r': + syscall.SetReadDeadline(fd.sysfd, d) + case 'w': + syscall.SetWriteDeadline(fd.sysfd, d) + case 'r' + 'w': + syscall.SetReadDeadline(fd.sysfd, d) + syscall.SetWriteDeadline(fd.sysfd, d) + } + fd.decref() + return nil +} diff --git a/libgo/go/net/fd_poll_runtime.go b/libgo/go/net/fd_poll_runtime.go index e2b2768864a..2bddc836c75 100644 --- a/libgo/go/net/fd_poll_runtime.go +++ b/libgo/go/net/fd_poll_runtime.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris package net @@ -12,6 +12,9 @@ import ( "time" ) +// runtimeNano returns the current value of the runtime clock in nanoseconds. +func runtimeNano() int64 + func runtime_pollServerInit() func runtime_pollOpen(fd uintptr) (uintptr, int) func runtime_pollClose(ctx uintptr) @@ -128,7 +131,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error { } func setDeadlineImpl(fd *netFD, t time.Time, mode int) error { - d := t.UnixNano() + d := runtimeNano() + int64(t.Sub(time.Now())) if t.IsZero() { d = 0 } diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go index a89303e37e9..ca6aac3b42e 100644 --- a/libgo/go/net/fd_unix.go +++ b/libgo/go/net/fd_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package net @@ -75,29 +75,47 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error { if err := fd.pd.PrepareWrite(); err != nil { return err } - for { - err := syscall.Connect(fd.sysfd, ra) - if err == nil || err == syscall.EISCONN { - break - } - + switch err := syscall.Connect(fd.sysfd, ra); err { + case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: + case nil, syscall.EISCONN: + return nil + case syscall.EINVAL: // On Solaris we can see EINVAL if the socket has // already been accepted and closed by the server. // Treat this as a successful connection--writes to // the socket will see EOF. For details and a test // case in C see http://golang.org/issue/6828. - if runtime.GOOS == "solaris" && err == syscall.EINVAL { - break + if runtime.GOOS == "solaris" { + return nil } - - if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR { + fallthrough + default: + return err + } + for { + // Performing multiple connect system calls on a + // non-blocking socket under Unix variants does not + // necessarily result in earlier errors being + // returned. Instead, once runtime-integrated network + // poller tells us that the socket is ready, get the + // SO_ERROR socket option to see if the connection + // succeeded or failed. See issue 7474 for further + // details. + if err := fd.pd.WaitWrite(); err != nil { return err } - if err = fd.pd.WaitWrite(); err != nil { + nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) + if err != nil { + return err + } + switch err := syscall.Errno(nerr); err { + case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: + case syscall.Errno(0), syscall.EISCONN: + return nil + default: return err } } - return nil } func (fd *netFD) destroy() { @@ -190,11 +208,11 @@ func (fd *netFD) shutdown(how int) error { return nil } -func (fd *netFD) CloseRead() error { +func (fd *netFD) closeRead() error { return fd.shutdown(syscall.SHUT_RD) } -func (fd *netFD) CloseWrite() error { +func (fd *netFD) closeWrite() error { return fd.shutdown(syscall.SHUT_WR) } @@ -225,7 +243,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) { return } -func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { +func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { if err := fd.readLock(); err != nil { return 0, nil, err } @@ -252,7 +270,7 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { return } -func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { +func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { if err := fd.readLock(); err != nil { return 0, 0, 0, nil, err } @@ -323,7 +341,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) { return nn, err } -func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { +func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { if err := fd.writeLock(); err != nil { return 0, err } @@ -348,7 +366,7 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { return } -func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { +func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { if err := fd.writeLock(); err != nil { return 0, 0, err } @@ -357,7 +375,7 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob return 0, 0, &OpError{"write", fd.net, fd.raddr, err} } for { - err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0) + n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0) if err == syscall.EAGAIN { if err = fd.pd.WaitWrite(); err == nil { continue @@ -366,7 +384,6 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob break } if err == nil { - n = len(p) oobn = len(oob) } else { err = &OpError{"write", fd.net, fd.raddr, err} @@ -465,7 +482,6 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) { func (fd *netFD) dup() (f *os.File, err error) { ns, err := dupCloseOnExec(fd.sysfd) if err != nil { - syscall.ForkLock.RUnlock() return nil, &OpError{"dup", fd.net, fd.laddr, err} } diff --git a/libgo/go/net/fd_unix_test.go b/libgo/go/net/fd_unix_test.go index 65d3e69a764..fe8e8ff6a88 100644 --- a/libgo/go/net/fd_unix_test.go +++ b/libgo/go/net/fd_unix_test.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go index 0f8d6de5b54..a1f6bc5f814 100644 --- a/libgo/go/net/fd_windows.go +++ b/libgo/go/net/fd_windows.go @@ -431,11 +431,11 @@ func (fd *netFD) shutdown(how int) error { return nil } -func (fd *netFD) CloseRead() error { +func (fd *netFD) closeRead() error { return fd.shutdown(syscall.SHUT_RD) } -func (fd *netFD) CloseWrite() error { +func (fd *netFD) closeWrite() error { return fd.shutdown(syscall.SHUT_WR) } @@ -458,7 +458,7 @@ func (fd *netFD) Read(buf []byte) (int, error) { return n, err } -func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) { +func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) { if len(buf) == 0 { return 0, nil, nil } @@ -497,7 +497,7 @@ func (fd *netFD) Write(buf []byte) (int, error) { }) } -func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) { +func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) { if len(buf) == 0 { return 0, nil } @@ -628,10 +628,10 @@ func (fd *netFD) dup() (*os.File, error) { var errNoSupport = errors.New("address family not supported") -func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { +func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { return 0, 0, 0, nil, errNoSupport } -func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { +func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { return 0, 0, errNoSupport } diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go index e4615b74fc3..d81bca78249 100644 --- a/libgo/go/net/file_test.go +++ b/libgo/go/net/file_test.go @@ -181,7 +181,7 @@ var filePacketConnTests = []struct { func TestFilePacketConn(t *testing.T) { switch runtime.GOOS { - case "plan9", "windows": + case "nacl", "plan9", "windows": t.Skipf("skipping test on %q", runtime.GOOS) } diff --git a/libgo/go/net/file_unix.go b/libgo/go/net/file_unix.go index 38ae47f7847..07b3ecf6263 100644 --- a/libgo/go/net/file_unix.go +++ b/libgo/go/net/file_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package net diff --git a/libgo/go/net/http/cgi/host.go b/libgo/go/net/http/cgi/host.go index d27cc4dc9a8..ec95a972c1a 100644 --- a/libgo/go/net/http/cgi/host.go +++ b/libgo/go/net/http/cgi/host.go @@ -214,12 +214,17 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { internalError(err) return } + if hook := testHookStartProcess; hook != nil { + hook(cmd.Process) + } defer cmd.Wait() defer stdoutRead.Close() linebody := bufio.NewReaderSize(stdoutRead, 1024) headers := make(http.Header) statusCode := 0 + headerLines := 0 + sawBlankLine := false for { line, isPrefix, err := linebody.ReadLine() if isPrefix { @@ -236,8 +241,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { return } if len(line) == 0 { + sawBlankLine = true break } + headerLines++ parts := strings.SplitN(string(line), ":", 2) if len(parts) < 2 { h.printf("cgi: bogus header line: %s", string(line)) @@ -263,6 +270,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { headers.Add(header, val) } } + if headerLines == 0 || !sawBlankLine { + rw.WriteHeader(http.StatusInternalServerError) + h.printf("cgi: no headers") + return + } if loc := headers.Get("Location"); loc != "" { if strings.HasPrefix(loc, "/") && h.PathLocationHandler != nil { @@ -274,6 +286,12 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } } + if statusCode == 0 && headers.Get("Content-Type") == "" { + rw.WriteHeader(http.StatusInternalServerError) + h.printf("cgi: missing required Content-Type in headers") + return + } + if statusCode == 0 { statusCode = http.StatusOK } @@ -292,6 +310,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { _, err = io.Copy(rw, linebody) if err != nil { h.printf("cgi: copy error: %v", err) + // And kill the child CGI process so we don't hang on + // the deferred cmd.Wait above if the error was just + // the client (rw) going away. If it was a read error + // (because the child died itself), then the extra + // kill of an already-dead process is harmless (the PID + // won't be reused until the Wait above). + cmd.Process.Kill() } } @@ -348,3 +373,5 @@ func upperCaseAndUnderscore(r rune) rune { // TODO: other transformations in spec or practice? return r } + +var testHookStartProcess func(*os.Process) // nil except for some tests diff --git a/libgo/go/net/http/cgi/matryoshka_test.go b/libgo/go/net/http/cgi/matryoshka_test.go index e1a78c8f62f..18c4803e71b 100644 --- a/libgo/go/net/http/cgi/matryoshka_test.go +++ b/libgo/go/net/http/cgi/matryoshka_test.go @@ -9,15 +9,25 @@ package cgi import ( + "bytes" + "errors" "fmt" + "io" "net/http" + "net/http/httptest" "os" + "runtime" "testing" + "time" ) // This test is a CGI host (testing host.go) that runs its own binary // as a child process testing the other half of CGI (child.go). func TestHostingOurselves(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + h := &Handler{ Path: os.Args[0], Root: "/test.go", @@ -51,8 +61,88 @@ func TestHostingOurselves(t *testing.T) { } } -// Test that a child handler only writing headers works. +type customWriterRecorder struct { + w io.Writer + *httptest.ResponseRecorder +} + +func (r *customWriterRecorder) Write(p []byte) (n int, err error) { + return r.w.Write(p) +} + +type limitWriter struct { + w io.Writer + n int +} + +func (w *limitWriter) Write(p []byte) (n int, err error) { + if len(p) > w.n { + p = p[:w.n] + } + if len(p) > 0 { + n, err = w.w.Write(p) + w.n -= n + } + if w.n == 0 { + err = errors.New("past write limit") + } + return +} + +// If there's an error copying the child's output to the parent, test +// that we kill the child. +func TestKillChildAfterCopyError(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + + defer func() { testHookStartProcess = nil }() + proc := make(chan *os.Process, 1) + testHookStartProcess = func(p *os.Process) { + proc <- p + } + + h := &Handler{ + Path: os.Args[0], + Root: "/test.go", + Args: []string{"-test.run=TestBeChildCGIProcess"}, + } + req, _ := http.NewRequest("GET", "http://example.com/test.cgi?write-forever=1", nil) + rec := httptest.NewRecorder() + var out bytes.Buffer + const writeLen = 50 << 10 + rw := &customWriterRecorder{&limitWriter{&out, writeLen}, rec} + + donec := make(chan bool, 1) + go func() { + h.ServeHTTP(rw, req) + donec <- true + }() + + select { + case <-donec: + if out.Len() != writeLen || out.Bytes()[0] != 'a' { + t.Errorf("unexpected output: %q", out.Bytes()) + } + case <-time.After(5 * time.Second): + t.Errorf("timeout. ServeHTTP hung and didn't kill the child process?") + select { + case p := <-proc: + p.Kill() + t.Logf("killed process") + default: + t.Logf("didn't kill process") + } + } +} + +// Test that a child handler writing only headers works. +// golang.org/issue/7196 func TestChildOnlyHeaders(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + h := &Handler{ Path: os.Args[0], Root: "/test.go", @@ -67,18 +157,63 @@ func TestChildOnlyHeaders(t *testing.T) { } } +// golang.org/issue/7198 +func Test500WithNoHeaders(t *testing.T) { want500Test(t, "/immediate-disconnect") } +func Test500WithNoContentType(t *testing.T) { want500Test(t, "/no-content-type") } +func Test500WithEmptyHeaders(t *testing.T) { want500Test(t, "/empty-headers") } + +func want500Test(t *testing.T, path string) { + h := &Handler{ + Path: os.Args[0], + Root: "/test.go", + Args: []string{"-test.run=TestBeChildCGIProcess"}, + } + expectedMap := map[string]string{ + "_body": "", + } + replay := runCgiTest(t, h, "GET "+path+" HTTP/1.0\nHost: example.com\n\n", expectedMap) + if replay.Code != 500 { + t.Errorf("Got code %d; want 500", replay.Code) + } +} + +type neverEnding byte + +func (b neverEnding) Read(p []byte) (n int, err error) { + for i := range p { + p[i] = byte(b) + } + return len(p), nil +} + // Note: not actually a test. func TestBeChildCGIProcess(t *testing.T) { if os.Getenv("REQUEST_METHOD") == "" { // Not in a CGI environment; skipping test. return } + switch os.Getenv("REQUEST_URI") { + case "/immediate-disconnect": + os.Exit(0) + case "/no-content-type": + fmt.Printf("Content-Length: 6\n\nHello\n") + os.Exit(0) + case "/empty-headers": + fmt.Printf("\nHello") + os.Exit(0) + } Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Set("X-Test-Header", "X-Test-Value") req.ParseForm() if req.FormValue("no-body") == "1" { return } + if req.FormValue("write-forever") == "1" { + io.Copy(rw, neverEnding('a')) + for { + time.Sleep(5 * time.Second) // hang forever, until killed + } + } fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n") for k, vv := range req.Form { for _, v := range vv { diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go index 22f2e865cf7..a5a3abe6138 100644 --- a/libgo/go/net/http/client.go +++ b/libgo/go/net/http/client.go @@ -14,9 +14,12 @@ import ( "errors" "fmt" "io" + "io/ioutil" "log" "net/url" "strings" + "sync" + "time" ) // A Client is an HTTP client. Its zero value (DefaultClient) is a @@ -52,6 +55,20 @@ type Client struct { // If Jar is nil, cookies are not sent in requests and ignored // in responses. Jar CookieJar + + // Timeout specifies a time limit for requests made by this + // Client. The timeout includes connection time, any + // redirects, and reading the response body. The timer remains + // running after Get, Head, Post, or Do return and will + // interrupt reading of the Response.Body. + // + // A Timeout of zero means no timeout. + // + // The Client's Transport must support the CancelRequest + // method or Client will return errors when attempting to make + // a request with Get, Head, Post, or Do. Client's default + // Transport (DefaultTransport) supports CancelRequest. + Timeout time.Duration } // DefaultClient is the default Client and is used by Get, Head, and Post. @@ -74,8 +91,9 @@ type RoundTripper interface { // authentication, or cookies. // // RoundTrip should not modify the request, except for - // consuming and closing the Body. The request's URL and - // Header fields are guaranteed to be initialized. + // consuming and closing the Body, including on errors. The + // request's URL and Header fields are guaranteed to be + // initialized. RoundTrip(*Request) (*Response, error) } @@ -97,7 +115,7 @@ func (c *Client) send(req *Request) (*Response, error) { req.AddCookie(cookie) } } - resp, err := send(req, c.Transport) + resp, err := send(req, c.transport()) if err != nil { return nil, err } @@ -123,6 +141,9 @@ func (c *Client) send(req *Request) (*Response, error) { // (typically Transport) may not be able to re-use a persistent TCP // connection to the server for a subsequent "keep-alive" request. // +// The request Body, if non-nil, will be closed by the underlying +// Transport, even on errors. +// // Generally Get, Post, or PostForm will be used instead of Do. func (c *Client) Do(req *Request) (resp *Response, err error) { if req.Method == "GET" || req.Method == "HEAD" { @@ -134,22 +155,28 @@ func (c *Client) Do(req *Request) (resp *Response, err error) { return c.send(req) } +func (c *Client) transport() RoundTripper { + if c.Transport != nil { + return c.Transport + } + return DefaultTransport +} + // send issues an HTTP request. // Caller should close resp.Body when done reading from it. func send(req *Request, t RoundTripper) (resp *Response, err error) { if t == nil { - t = DefaultTransport - if t == nil { - err = errors.New("http: no Client.Transport or DefaultTransport") - return - } + req.closeBody() + return nil, errors.New("http: no Client.Transport or DefaultTransport") } if req.URL == nil { + req.closeBody() return nil, errors.New("http: nil Request.URL") } if req.RequestURI != "" { + req.closeBody() return nil, errors.New("http: Request.RequestURI can't be set in client requests.") } @@ -257,21 +284,40 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo var via []*Request if ireq.URL == nil { + ireq.closeBody() return nil, errors.New("http: nil Request.URL") } + var reqmu sync.Mutex // guards req req := ireq + + var timer *time.Timer + if c.Timeout > 0 { + type canceler interface { + CancelRequest(*Request) + } + tr, ok := c.transport().(canceler) + if !ok { + return nil, fmt.Errorf("net/http: Client Transport of type %T doesn't support CancelRequest; Timeout not supported", c.transport()) + } + timer = time.AfterFunc(c.Timeout, func() { + reqmu.Lock() + defer reqmu.Unlock() + tr.CancelRequest(req) + }) + } + urlStr := "" // next relative or absolute URL to fetch (after first request) redirectFailed := false for redirect := 0; ; redirect++ { if redirect != 0 { - req = new(Request) - req.Method = ireq.Method + nreq := new(Request) + nreq.Method = ireq.Method if ireq.Method == "POST" || ireq.Method == "PUT" { - req.Method = "GET" + nreq.Method = "GET" } - req.Header = make(Header) - req.URL, err = base.Parse(urlStr) + nreq.Header = make(Header) + nreq.URL, err = base.Parse(urlStr) if err != nil { break } @@ -279,15 +325,18 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo // Add the Referer header. lastReq := via[len(via)-1] if lastReq.URL.Scheme != "https" { - req.Header.Set("Referer", lastReq.URL.String()) + nreq.Header.Set("Referer", lastReq.URL.String()) } - err = redirectChecker(req, via) + err = redirectChecker(nreq, via) if err != nil { redirectFailed = true break } } + reqmu.Lock() + req = nreq + reqmu.Unlock() } urlStr = req.URL.String() @@ -296,6 +345,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo } if shouldRedirect(resp.StatusCode) { + // Read the body if small so underlying TCP connection will be re-used. + // No need to check for errors: if it fails, Transport won't reuse it anyway. + const maxBodySlurpSize = 2 << 10 + if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize { + io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize) + } resp.Body.Close() if urlStr = resp.Header.Get("Location"); urlStr == "" { err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode)) @@ -305,7 +360,10 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo via = append(via, req) continue } - return + if timer != nil { + resp.Body = &cancelTimerBody{timer, resp.Body} + } + return resp, nil } method := ireq.Method @@ -349,7 +407,7 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro // Caller should close resp.Body when done reading from it. // // If the provided body is also an io.Closer, it is closed after the -// body is successfully written to the server. +// request. func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) { req, err := NewRequest("POST", url, body) if err != nil { @@ -408,3 +466,22 @@ func (c *Client) Head(url string) (resp *Response, err error) { } return c.doFollowingRedirects(req, shouldRedirectGet) } + +type cancelTimerBody struct { + t *time.Timer + rc io.ReadCloser +} + +func (b *cancelTimerBody) Read(p []byte) (n int, err error) { + n, err = b.rc.Read(p) + if err == io.EOF { + b.t.Stop() + } + return +} + +func (b *cancelTimerBody) Close() error { + err := b.rc.Close() + b.t.Stop() + return err +} diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go index e5ad39c7741..6392c1baf39 100644 --- a/libgo/go/net/http/client_test.go +++ b/libgo/go/net/http/client_test.go @@ -15,14 +15,18 @@ import ( "fmt" "io" "io/ioutil" + "log" "net" . "net/http" "net/http/httptest" "net/url" + "reflect" + "sort" "strconv" "strings" "sync" "testing" + "time" ) var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) { @@ -54,6 +58,13 @@ func pedanticReadAll(r io.Reader) (b []byte, err error) { } } +type chanWriter chan string + +func (w chanWriter) Write(p []byte) (n int, err error) { + w <- string(p) + return len(p), nil +} + func TestClient(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(robotsTxtHandler) @@ -564,6 +575,8 @@ func TestClientInsecureTransport(t *testing.T) { ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { w.Write([]byte("Hello")) })) + errc := make(chanWriter, 10) // but only expecting 1 + ts.Config.ErrorLog = log.New(errc, "", 0) defer ts.Close() // TODO(bradfitz): add tests for skipping hostname checks too? @@ -585,6 +598,16 @@ func TestClientInsecureTransport(t *testing.T) { res.Body.Close() } } + + select { + case v := <-errc: + if !strings.Contains(v, "TLS handshake error") { + t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v) + } + case <-time.After(5 * time.Second): + t.Errorf("timeout waiting for logged error") + } + } func TestClientErrorWithRequestURI(t *testing.T) { @@ -635,6 +658,8 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) { defer afterTest(t) ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) defer ts.Close() + errc := make(chanWriter, 10) // but only expecting 1 + ts.Config.ErrorLog = log.New(errc, "", 0) trans := newTLSTransport(t, ts) trans.TLSClientConfig.ServerName = "badserver" @@ -646,6 +671,14 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) { if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") { t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err) } + select { + case v := <-errc: + if !strings.Contains(v, "TLS handshake error") { + t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v) + } + case <-time.After(5 * time.Second): + t.Errorf("timeout waiting for logged error") + } } // Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName @@ -678,6 +711,33 @@ func TestTransportUsesTLSConfigServerName(t *testing.T) { res.Body.Close() } +func TestResponseSetsTLSConnectionState(t *testing.T) { + defer afterTest(t) + ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Write([]byte("Hello")) + })) + defer ts.Close() + + tr := newTLSTransport(t, ts) + tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA} + tr.Dial = func(netw, addr string) (net.Conn, error) { + return net.Dial(netw, ts.Listener.Addr().String()) + } + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + res, err := c.Get("https://example.com/") + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + if res.TLS == nil { + t.Fatal("Response didn't set TLS Connection State.") + } + if got, want := res.TLS.CipherSuite, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA; got != want { + t.Errorf("TLS Cipher Suite = %d; want %d", got, want) + } +} + // Verify Response.ContentLength is populated. http://golang.org/issue/4126 func TestClientHeadContentLength(t *testing.T) { defer afterTest(t) @@ -781,3 +841,198 @@ func TestBasicAuth(t *testing.T) { t.Errorf("Invalid auth %q", auth) } } + +func TestClientTimeout(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + defer afterTest(t) + sawRoot := make(chan bool, 1) + sawSlow := make(chan bool, 1) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + if r.URL.Path == "/" { + sawRoot <- true + Redirect(w, r, "/slow", StatusFound) + return + } + if r.URL.Path == "/slow" { + w.Write([]byte("Hello")) + w.(Flusher).Flush() + sawSlow <- true + time.Sleep(2 * time.Second) + return + } + })) + defer ts.Close() + const timeout = 500 * time.Millisecond + c := &Client{ + Timeout: timeout, + } + + res, err := c.Get(ts.URL) + if err != nil { + t.Fatal(err) + } + + select { + case <-sawRoot: + // good. + default: + t.Fatal("handler never got / request") + } + + select { + case <-sawSlow: + // good. + default: + t.Fatal("handler never got /slow request") + } + + errc := make(chan error, 1) + go func() { + _, err := ioutil.ReadAll(res.Body) + errc <- err + res.Body.Close() + }() + + const failTime = timeout * 2 + select { + case err := <-errc: + if err == nil { + t.Error("expected error from ReadAll") + } + // Expected error. + case <-time.After(failTime): + t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout) + } +} + +func TestClientRedirectEatsBody(t *testing.T) { + defer afterTest(t) + saw := make(chan string, 2) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + saw <- r.RemoteAddr + if r.URL.Path == "/" { + Redirect(w, r, "/foo", StatusFound) // which includes a body + } + })) + defer ts.Close() + + res, err := Get(ts.URL) + if err != nil { + t.Fatal(err) + } + _, err = ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + + var first string + select { + case first = <-saw: + default: + t.Fatal("server didn't see a request") + } + + var second string + select { + case second = <-saw: + default: + t.Fatal("server didn't see a second request") + } + + if first != second { + t.Fatal("server saw different client ports before & after the redirect") + } +} + +// eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF. +type eofReaderFunc func() + +func (f eofReaderFunc) Read(p []byte) (n int, err error) { + f() + return 0, io.EOF +} + +func TestClientTrailers(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Connection", "close") + w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B") + w.Header().Add("Trailer", "Server-Trailer-C") + + var decl []string + for k := range r.Trailer { + decl = append(decl, k) + } + sort.Strings(decl) + + slurp, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Errorf("Server reading request body: %v", err) + } + if string(slurp) != "foo" { + t.Errorf("Server read request body %q; want foo", slurp) + } + if r.Trailer == nil { + io.WriteString(w, "nil Trailer") + } else { + fmt.Fprintf(w, "decl: %v, vals: %s, %s", + decl, + r.Trailer.Get("Client-Trailer-A"), + r.Trailer.Get("Client-Trailer-B")) + } + + // TODO: golang.org/issue/7759: there's no way yet for + // the server to set trailers without hijacking, so do + // that for now, just to test the client. Later, in + // Go 1.4, it should be implicit that any mutations + // to w.Header() after the initial write are the + // trailers to be sent, if and only if they were + // previously declared with w.Header().Set("Trailer", + // ..keys..) + w.(Flusher).Flush() + conn, buf, _ := w.(Hijacker).Hijack() + t := Header{} + t.Set("Server-Trailer-A", "valuea") + t.Set("Server-Trailer-C", "valuec") // skipping B + buf.WriteString("0\r\n") // eof + t.Write(buf) + buf.WriteString("\r\n") // end of trailers + buf.Flush() + conn.Close() + })) + defer ts.Close() + + var req *Request + req, _ = NewRequest("POST", ts.URL, io.MultiReader( + eofReaderFunc(func() { + req.Trailer["Client-Trailer-A"] = []string{"valuea"} + }), + strings.NewReader("foo"), + eofReaderFunc(func() { + req.Trailer["Client-Trailer-B"] = []string{"valueb"} + }), + )) + req.Trailer = Header{ + "Client-Trailer-A": nil, // to be set later + "Client-Trailer-B": nil, // to be set later + } + req.ContentLength = -1 + res, err := DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + if err := wantBody(res, err, "decl: [Client-Trailer-A Client-Trailer-B], vals: valuea, valueb"); err != nil { + t.Error(err) + } + want := Header{ + "Server-Trailer-A": []string{"valuea"}, + "Server-Trailer-B": nil, + "Server-Trailer-C": []string{"valuec"}, + } + if !reflect.DeepEqual(res.Trailer, want) { + t.Errorf("Response trailers = %#v; want %#v", res.Trailer, want) + } +} diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go index a1759214f38..dc60ba87f5f 100644 --- a/libgo/go/net/http/cookie.go +++ b/libgo/go/net/http/cookie.go @@ -76,11 +76,7 @@ func readSetCookies(h Header) []*Cookie { attr, val = attr[:j], attr[j+1:] } lowerAttr := strings.ToLower(attr) - parseCookieValueFn := parseCookieValue - if lowerAttr == "expires" { - parseCookieValueFn = parseCookieExpiresValue - } - val, success = parseCookieValueFn(val) + val, success = parseCookieValue(val) if !success { c.Unparsed = append(c.Unparsed, parts[i]) continue @@ -298,12 +294,23 @@ func sanitizeCookieName(n string) string { // ; US-ASCII characters excluding CTLs, // ; whitespace DQUOTE, comma, semicolon, // ; and backslash +// We loosen this as spaces and commas are common in cookie values +// but we produce a quoted cookie-value in when value starts or ends +// with a comma or space. +// See http://golang.org/issue/7243 for the discussion. func sanitizeCookieValue(v string) string { - return sanitizeOrWarn("Cookie.Value", validCookieValueByte, v) + v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v) + if len(v) == 0 { + return v + } + if v[0] == ' ' || v[0] == ',' || v[len(v)-1] == ' ' || v[len(v)-1] == ',' { + return `"` + v + `"` + } + return v } func validCookieValueByte(b byte) bool { - return 0x20 < b && b < 0x7f && b != '"' && b != ',' && b != ';' && b != '\\' + return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\' } // path-av = "Path=" path-value @@ -338,38 +345,13 @@ func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string { return string(buf) } -func unquoteCookieValue(v string) string { - if len(v) > 1 && v[0] == '"' && v[len(v)-1] == '"' { - return v[1 : len(v)-1] - } - return v -} - -func isCookieByte(c byte) bool { - switch { - case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a, - 0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e: - return true - } - return false -} - -func isCookieExpiresByte(c byte) (ok bool) { - return isCookieByte(c) || c == ',' || c == ' ' -} - func parseCookieValue(raw string) (string, bool) { - return parseCookieValueUsing(raw, isCookieByte) -} - -func parseCookieExpiresValue(raw string) (string, bool) { - return parseCookieValueUsing(raw, isCookieExpiresByte) -} - -func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) { - raw = unquoteCookieValue(raw) + // Strip the quotes, if present. + if len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' { + raw = raw[1 : len(raw)-1] + } for i := 0; i < len(raw); i++ { - if !validByte(raw[i]) { + if !validCookieValueByte(raw[i]) { return "", false } } diff --git a/libgo/go/net/http/cookie_test.go b/libgo/go/net/http/cookie_test.go index 1aa9d49d96e..f78f37299f4 100644 --- a/libgo/go/net/http/cookie_test.go +++ b/libgo/go/net/http/cookie_test.go @@ -52,6 +52,44 @@ var writeSetCookiesTests = []struct { &Cookie{Name: "cookie-8", Value: "eight", Domain: "::1"}, "cookie-8=eight", }, + // The "special" cookies have values containing commas or spaces which + // are disallowed by RFC 6265 but are common in the wild. + { + &Cookie{Name: "special-1", Value: "a z"}, + `special-1=a z`, + }, + { + &Cookie{Name: "special-2", Value: " z"}, + `special-2=" z"`, + }, + { + &Cookie{Name: "special-3", Value: "a "}, + `special-3="a "`, + }, + { + &Cookie{Name: "special-4", Value: " "}, + `special-4=" "`, + }, + { + &Cookie{Name: "special-5", Value: "a,z"}, + `special-5=a,z`, + }, + { + &Cookie{Name: "special-6", Value: ",z"}, + `special-6=",z"`, + }, + { + &Cookie{Name: "special-7", Value: "a,"}, + `special-7="a,"`, + }, + { + &Cookie{Name: "special-8", Value: ","}, + `special-8=","`, + }, + { + &Cookie{Name: "empty-value", Value: ""}, + `empty-value=`, + }, } func TestWriteSetCookies(t *testing.T) { @@ -178,6 +216,40 @@ var readSetCookiesTests = []struct { Raw: "ASP.NET_SessionId=foo; path=/; HttpOnly", }}, }, + // Make sure we can properly read back the Set-Cookie headers we create + // for values containing spaces or commas: + { + Header{"Set-Cookie": {`special-1=a z`}}, + []*Cookie{{Name: "special-1", Value: "a z", Raw: `special-1=a z`}}, + }, + { + Header{"Set-Cookie": {`special-2=" z"`}}, + []*Cookie{{Name: "special-2", Value: " z", Raw: `special-2=" z"`}}, + }, + { + Header{"Set-Cookie": {`special-3="a "`}}, + []*Cookie{{Name: "special-3", Value: "a ", Raw: `special-3="a "`}}, + }, + { + Header{"Set-Cookie": {`special-4=" "`}}, + []*Cookie{{Name: "special-4", Value: " ", Raw: `special-4=" "`}}, + }, + { + Header{"Set-Cookie": {`special-5=a,z`}}, + []*Cookie{{Name: "special-5", Value: "a,z", Raw: `special-5=a,z`}}, + }, + { + Header{"Set-Cookie": {`special-6=",z"`}}, + []*Cookie{{Name: "special-6", Value: ",z", Raw: `special-6=",z"`}}, + }, + { + Header{"Set-Cookie": {`special-7=a,`}}, + []*Cookie{{Name: "special-7", Value: "a,", Raw: `special-7=a,`}}, + }, + { + Header{"Set-Cookie": {`special-8=","`}}, + []*Cookie{{Name: "special-8", Value: ",", Raw: `special-8=","`}}, + }, // TODO(bradfitz): users have reported seeing this in the // wild, but do browsers handle it? RFC 6265 just says "don't @@ -264,9 +336,14 @@ func TestCookieSanitizeValue(t *testing.T) { in, want string }{ {"foo", "foo"}, - {"foo bar", "foobar"}, + {"foo;bar", "foobar"}, + {"foo\\bar", "foobar"}, + {"foo\"bar", "foobar"}, {"\x00\x7e\x7f\x80", "\x7e"}, {`"withquotes"`, "withquotes"}, + {"a z", "a z"}, + {" z", `" z"`}, + {"a ", `"a "`}, } for _, tt := range tests { if got := sanitizeCookieValue(tt.in); got != tt.want { diff --git a/libgo/go/net/http/export_test.go b/libgo/go/net/http/export_test.go index 8074df5bbde..960563b2409 100644 --- a/libgo/go/net/http/export_test.go +++ b/libgo/go/net/http/export_test.go @@ -21,7 +21,7 @@ var ExportAppendTime = appendTime func (t *Transport) NumPendingRequestsForTesting() int { t.reqMu.Lock() defer t.reqMu.Unlock() - return len(t.reqConn) + return len(t.reqCanceler) } func (t *Transport) IdleConnKeysForTesting() (keys []string) { diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go index 60b794e0775..a3beaa33a86 100644 --- a/libgo/go/net/http/fcgi/child.go +++ b/libgo/go/net/http/fcgi/child.go @@ -16,6 +16,7 @@ import ( "net/http/cgi" "os" "strings" + "sync" "time" ) @@ -126,8 +127,10 @@ func (r *response) Close() error { } type child struct { - conn *conn - handler http.Handler + conn *conn + handler http.Handler + + mu sync.Mutex // protects requests: requests map[uint16]*request // keyed by request ID } @@ -157,7 +160,9 @@ var errCloseConn = errors.New("fcgi: connection should be closed") var emptyBody = ioutil.NopCloser(strings.NewReader("")) func (c *child) handleRecord(rec *record) error { + c.mu.Lock() req, ok := c.requests[rec.h.Id] + c.mu.Unlock() if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues { // The spec says to ignore unknown request IDs. return nil @@ -179,7 +184,10 @@ func (c *child) handleRecord(rec *record) error { c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole) return nil } - c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags) + req = newRequest(rec.h.Id, br.flags) + c.mu.Lock() + c.requests[rec.h.Id] = req + c.mu.Unlock() return nil case typeParams: // NOTE(eds): Technically a key-value pair can straddle the boundary @@ -220,7 +228,9 @@ func (c *child) handleRecord(rec *record) error { return nil case typeAbortRequest: println("abort") + c.mu.Lock() delete(c.requests, rec.h.Id) + c.mu.Unlock() c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete) if !req.keepConn { // connection will close upon return @@ -247,6 +257,9 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) { c.handler.ServeHTTP(r, httpReq) } r.Close() + c.mu.Lock() + delete(c.requests, req.reqId) + c.mu.Unlock() c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete) // Consume the entire body, so the host isn't still writing to diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go index 9df5cc48189..8576cf844a3 100644 --- a/libgo/go/net/http/fs.go +++ b/libgo/go/net/http/fs.go @@ -527,7 +527,7 @@ func (w *countingWriter) Write(p []byte) (n int, err error) { return len(p), nil } -// rangesMIMESize returns the nunber of bytes it takes to encode the +// rangesMIMESize returns the number of bytes it takes to encode the // provided ranges as a multipart response. func rangesMIMESize(ranges []httpRange, contentType string, contentSize int64) (encSize int64) { var w countingWriter diff --git a/libgo/go/net/http/header.go b/libgo/go/net/http/header.go index de62bef5525..153b94370f8 100644 --- a/libgo/go/net/http/header.go +++ b/libgo/go/net/http/header.go @@ -13,6 +13,8 @@ import ( "time" ) +var raceEnabled = false // set by race.go + // A Header represents the key-value pairs in an HTTP header. type Header map[string][]string diff --git a/libgo/go/net/http/header_test.go b/libgo/go/net/http/header_test.go index 2c896c5ad23..299576ba8cf 100644 --- a/libgo/go/net/http/header_test.go +++ b/libgo/go/net/http/header_test.go @@ -192,9 +192,12 @@ func BenchmarkHeaderWriteSubset(b *testing.B) { } } -func TestHeaderWriteSubsetMallocs(t *testing.T) { +func TestHeaderWriteSubsetAllocs(t *testing.T) { if testing.Short() { - t.Skip("skipping malloc count in short mode") + t.Skip("skipping alloc test in short mode") + } + if raceEnabled { + t.Skip("skipping test under race detector") } t.Skip("Skipping alloc count test on gccgo") if runtime.GOMAXPROCS(0) > 1 { @@ -205,6 +208,6 @@ func TestHeaderWriteSubsetMallocs(t *testing.T) { testHeader.WriteSubset(&buf, nil) }) if n > 0 { - t.Errorf("mallocs = %g; want 0", n) + t.Errorf("allocs = %g; want 0", n) } } diff --git a/libgo/go/net/http/httptest/server_test.go b/libgo/go/net/http/httptest/server_test.go index 500a9f0b800..501cc8a9995 100644 --- a/libgo/go/net/http/httptest/server_test.go +++ b/libgo/go/net/http/httptest/server_test.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "net/http" "testing" + "time" ) func TestServer(t *testing.T) { @@ -27,3 +28,25 @@ func TestServer(t *testing.T) { t.Errorf("got %q, want hello", string(got)) } } + +func TestIssue7264(t *testing.T) { + for i := 0; i < 1000; i++ { + func() { + inHandler := make(chan bool, 1) + ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + inHandler <- true + })) + defer ts.Close() + tr := &http.Transport{ + ResponseHeaderTimeout: time.Nanosecond, + } + defer tr.CloseIdleConnections() + c := &http.Client{Transport: tr} + res, err := c.Get(ts.URL) + <-inHandler + if err == nil { + res.Body.Close() + } + }() + } +} diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go index ab1eab21bc6..2a7a413d01a 100644 --- a/libgo/go/net/http/httputil/dump.go +++ b/libgo/go/net/http/httputil/dump.go @@ -7,6 +7,7 @@ package httputil import ( "bufio" "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -106,6 +107,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil }, } + defer t.CloseIdleConnections() _, err := t.RoundTrip(reqSend) @@ -230,14 +232,31 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) { return } +// errNoBody is a sentinel error value used by failureToReadBody so we can detect +// that the lack of body was intentional. +var errNoBody = errors.New("sentinel error value") + +// failureToReadBody is a io.ReadCloser that just returns errNoBody on +// Read. It's swapped in when we don't actually want to consume the +// body, but need a non-nil one, and want to distinguish the error +// from reading the dummy body. +type failureToReadBody struct{} + +func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody } +func (failureToReadBody) Close() error { return nil } + +var emptyBody = ioutil.NopCloser(strings.NewReader("")) + // DumpResponse is like DumpRequest but dumps a response. func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) { var b bytes.Buffer save := resp.Body savecl := resp.ContentLength - if !body || resp.Body == nil { - resp.Body = nil - resp.ContentLength = 0 + + if !body { + resp.Body = failureToReadBody{} + } else if resp.Body == nil { + resp.Body = emptyBody } else { save, resp.Body, err = drainBody(resp.Body) if err != nil { @@ -245,11 +264,13 @@ func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) { } } err = resp.Write(&b) + if err == errNoBody { + err = nil + } resp.Body = save resp.ContentLength = savecl if err != nil { - return + return nil, err } - dump = b.Bytes() - return + return b.Bytes(), nil } diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go index a1dbfc39d6b..e1ffb3935ac 100644 --- a/libgo/go/net/http/httputil/dump_test.go +++ b/libgo/go/net/http/httputil/dump_test.go @@ -11,6 +11,8 @@ import ( "io/ioutil" "net/http" "net/url" + "runtime" + "strings" "testing" ) @@ -112,6 +114,7 @@ var dumpTests = []dumpTest{ } func TestDumpRequest(t *testing.T) { + numg0 := runtime.NumGoroutine() for i, tt := range dumpTests { setBody := func() { if tt.Body == nil { @@ -155,6 +158,9 @@ func TestDumpRequest(t *testing.T) { } } } + if dg := runtime.NumGoroutine() - numg0; dg > 4 { + t.Errorf("Unexpectedly large number of new goroutines: %d new", dg) + } } func chunk(s string) string { @@ -176,3 +182,82 @@ func mustNewRequest(method, url string, body io.Reader) *http.Request { } return req } + +var dumpResTests = []struct { + res *http.Response + body bool + want string +}{ + { + res: &http.Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + ContentLength: 50, + Header: http.Header{ + "Foo": []string{"Bar"}, + }, + Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used + }, + body: false, // to verify we see 50, not empty or 3. + want: `HTTP/1.1 200 OK +Content-Length: 50 +Foo: Bar`, + }, + + { + res: &http.Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + ContentLength: 3, + Body: ioutil.NopCloser(strings.NewReader("foo")), + }, + body: true, + want: `HTTP/1.1 200 OK +Content-Length: 3 + +foo`, + }, + + { + res: &http.Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + ContentLength: -1, + Body: ioutil.NopCloser(strings.NewReader("foo")), + TransferEncoding: []string{"chunked"}, + }, + body: true, + want: `HTTP/1.1 200 OK +Transfer-Encoding: chunked + +3 +foo +0`, + }, +} + +func TestDumpResponse(t *testing.T) { + for i, tt := range dumpResTests { + gotb, err := DumpResponse(tt.res, tt.body) + if err != nil { + t.Errorf("%d. DumpResponse = %v", i, err) + continue + } + got := string(gotb) + got = strings.TrimSpace(got) + got = strings.Replace(got, "\r", "", -1) + + if got != tt.want { + t.Errorf("%d.\nDumpResponse got:\n%s\n\nWant:\n%s\n", i, got, tt.want) + } + } +} diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go index 86d23e03706..987bcc96ba1 100644 --- a/libgo/go/net/http/httputil/persist.go +++ b/libgo/go/net/http/httputil/persist.go @@ -31,8 +31,8 @@ var errClosed = errors.New("i/o operation on closed connection") // i.e. requests can be read out of sync (but in the same order) while the // respective responses are sent. // -// ServerConn is low-level and should not be needed by most applications. -// See Server. +// ServerConn is low-level and old. Applications should instead use Server +// in the net/http package. type ServerConn struct { lk sync.Mutex // read-write protects the following fields c net.Conn @@ -45,8 +45,11 @@ type ServerConn struct { pipe textproto.Pipeline } -// NewServerConn returns a new ServerConn reading and writing c. If r is not +// NewServerConn returns a new ServerConn reading and writing c. If r is not // nil, it is the buffer to use when reading c. +// +// ServerConn is low-level and old. Applications should instead use Server +// in the net/http package. func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn { if r == nil { r = bufio.NewReader(c) @@ -221,8 +224,8 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error { // supports hijacking the connection calling Hijack to // regain control of the underlying net.Conn and deal with it as desired. // -// ClientConn is low-level and should not be needed by most applications. -// See Client. +// ClientConn is low-level and old. Applications should instead use +// Client or Transport in the net/http package. type ClientConn struct { lk sync.Mutex // read-write protects the following fields c net.Conn @@ -238,6 +241,9 @@ type ClientConn struct { // NewClientConn returns a new ClientConn reading and writing c. If r is not // nil, it is the buffer to use when reading c. +// +// ClientConn is low-level and old. Applications should use Client or +// Transport in the net/http package. func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn { if r == nil { r = bufio.NewReader(c) @@ -252,6 +258,9 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn { // NewProxyClientConn works like NewClientConn but writes Requests // using Request's WriteProxy method. +// +// New code should not use NewProxyClientConn. See Client or +// Transport in the net/http package instead. func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn { cc := NewClientConn(c, r) cc.writeReq = (*http.Request).WriteProxy diff --git a/libgo/go/net/http/proxy_test.go b/libgo/go/net/http/proxy_test.go index d0726f61f3b..b6aed3792b6 100644 --- a/libgo/go/net/http/proxy_test.go +++ b/libgo/go/net/http/proxy_test.go @@ -35,12 +35,8 @@ var UseProxyTests = []struct { } func TestUseProxy(t *testing.T) { - oldenv := os.Getenv("NO_PROXY") - defer os.Setenv("NO_PROXY", oldenv) - - no_proxy := "foobar.com, .barbaz.net" - os.Setenv("NO_PROXY", no_proxy) - + ResetProxyEnv() + os.Setenv("NO_PROXY", "foobar.com, .barbaz.net") for _, test := range UseProxyTests { if useProxy(test.host+":80") != test.match { t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match) @@ -76,3 +72,10 @@ func TestCacheKeys(t *testing.T) { } } } + +func ResetProxyEnv() { + for _, v := range []string{"HTTP_PROXY", "http_proxy", "NO_PROXY", "no_proxy"} { + os.Setenv(v, "") + } + ResetCachedEnvironment() +} diff --git a/libgo/go/net/http/race.go b/libgo/go/net/http/race.go new file mode 100644 index 00000000000..766503967c3 --- /dev/null +++ b/libgo/go/net/http/race.go @@ -0,0 +1,11 @@ +// Copyright 2014 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 race + +package http + +func init() { + raceEnabled = true +} diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 7a97770314d..a67092066ad 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -69,18 +69,31 @@ var reqWriteExcludeHeader = map[string]bool{ // A Request represents an HTTP request received by a server // or to be sent by a client. +// +// The field semantics differ slightly between client and server +// usage. In addition to the notes on the fields below, see the +// documentation for Request.Write and RoundTripper. type Request struct { - Method string // GET, POST, PUT, etc. + // Method specifies the HTTP method (GET, POST, PUT, etc.). + // For client requests an empty string means GET. + Method string - // URL is created from the URI supplied on the Request-Line - // as stored in RequestURI. + // URL specifies either the URI being requested (for server + // requests) or the URL to access (for client requests). + // + // For server requests the URL is parsed from the URI + // supplied on the Request-Line as stored in RequestURI. For + // most requests, fields other than Path and RawQuery will be + // empty. (See RFC 2616, Section 5.1.2) // - // For most requests, fields other than Path and RawQuery - // will be empty. (See RFC 2616, Section 5.1.2) + // For client requests, the URL's Host specifies the server to + // connect to, while the Request's Host field optionally + // specifies the Host header value to send in the HTTP + // request. URL *url.URL // The protocol version for incoming requests. - // Outgoing requests always use HTTP/1.1. + // Client requests always use HTTP/1.1. Proto string // "HTTP/1.0" ProtoMajor int // 1 ProtoMinor int // 0 @@ -104,15 +117,20 @@ type Request struct { // The request parser implements this by canonicalizing the // name, making the first character and any characters // following a hyphen uppercase and the rest lowercase. + // + // For client requests certain headers are automatically + // added and may override values in Header. + // + // See the documentation for the Request.Write method. Header Header // Body is the request's body. // - // For client requests, a nil body means the request has no + // For client requests a nil body means the request has no // body, such as a GET request. The HTTP Client's Transport // is responsible for calling the Close method. // - // For server requests, the Request Body is always non-nil + // For server requests the Request Body is always non-nil // but will return EOF immediately when no body is present. // The Server will close the request body. The ServeHTTP // Handler does not need to. @@ -122,7 +140,7 @@ type Request struct { // The value -1 indicates that the length is unknown. // Values >= 0 indicate that the given number of bytes may // be read from Body. - // For outgoing requests, a value of 0 means unknown if Body is not nil. + // For client requests, a value of 0 means unknown if Body is not nil. ContentLength int64 // TransferEncoding lists the transfer encodings from outermost to @@ -133,13 +151,18 @@ type Request struct { TransferEncoding []string // Close indicates whether to close the connection after - // replying to this request. + // replying to this request (for servers) or after sending + // the request (for clients). Close bool - // The host on which the URL is sought. - // Per RFC 2616, this is either the value of the Host: header - // or the host name given in the URL itself. + // For server requests Host specifies the host on which the + // URL is sought. Per RFC 2616, this is either the value of + // the "Host" header or the host name given in the URL itself. // It may be of the form "host:port". + // + // For client requests Host optionally overrides the Host + // header to send. If empty, the Request.Write method uses + // the value of URL.Host. Host string // Form contains the parsed form data, including both the URL @@ -159,12 +182,24 @@ type Request struct { // The HTTP client ignores MultipartForm and uses Body instead. MultipartForm *multipart.Form - // Trailer maps trailer keys to values. Like for Header, if the - // response has multiple trailer lines with the same key, they will be - // concatenated, delimited by commas. - // For server requests, Trailer is only populated after Body has been - // closed or fully consumed. - // Trailer support is only partially complete. + // Trailer specifies additional headers that are sent after the request + // body. + // + // For server requests the Trailer map initially contains only the + // trailer keys, with nil values. (The client declares which trailers it + // will later send.) While the handler is reading from Body, it must + // not reference Trailer. After reading from Body returns EOF, Trailer + // can be read again and will contain non-nil values, if they were sent + // by the client. + // + // For client requests Trailer must be initialized to a map containing + // the trailer keys to later send. The values may be nil or their final + // values. The ContentLength must be 0 or -1, to send a chunked request. + // After the HTTP request is sent the map values can be updated while + // the request body is read. Once the body returns EOF, the caller must + // not mutate Trailer. + // + // Few HTTP clients, servers, or proxies support HTTP trailers. Trailer Header // RemoteAddr allows HTTP servers and other software to record @@ -382,7 +417,6 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err return err } - // TODO: split long values? (If so, should share code with Conn.Write) err = req.Header.WriteSubset(w, reqWriteExcludeHeader) if err != nil { return err @@ -584,32 +618,6 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) { fixPragmaCacheControl(req.Header) - // TODO: Parse specific header values: - // Accept - // Accept-Encoding - // Accept-Language - // Authorization - // Cache-Control - // Connection - // Date - // Expect - // From - // If-Match - // If-Modified-Since - // If-None-Match - // If-Range - // If-Unmodified-Since - // Max-Forwards - // Proxy-Authorization - // Referer [sic] - // TE (transfer-codings) - // Trailer - // Transfer-Encoding - // Upgrade - // User-Agent - // Via - // Warning - err = readTransfer(req, b) if err != nil { return nil, err @@ -728,7 +736,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) { func (r *Request) ParseForm() error { var err error if r.PostForm == nil { - if r.Method == "POST" || r.Method == "PUT" { + if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" { r.PostForm, err = parsePostForm(r) } if r.PostForm == nil { @@ -781,9 +789,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error { } mr, err := r.multipartReader() - if err == ErrNotMultipart { - return nil - } else if err != nil { + if err != nil { return err } @@ -861,3 +867,9 @@ func (r *Request) wantsHttp10KeepAlive() bool { func (r *Request) wantsClose() bool { return hasToken(r.Header.get("Connection"), "close") } + +func (r *Request) closeBody() { + if r.Body != nil { + r.Body.Close() + } +} diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go index 68d141398aa..b9fa3c2bfc4 100644 --- a/libgo/go/net/http/request_test.go +++ b/libgo/go/net/http/request_test.go @@ -60,6 +60,37 @@ func TestPostQuery(t *testing.T) { } } +func TestPatchQuery(t *testing.T) { + req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not", + strings.NewReader("z=post&both=y&prio=2&empty=")) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") + + if q := req.FormValue("q"); q != "foo" { + t.Errorf(`req.FormValue("q") = %q, want "foo"`, q) + } + if z := req.FormValue("z"); z != "post" { + t.Errorf(`req.FormValue("z") = %q, want "post"`, z) + } + if bq, found := req.PostForm["q"]; found { + t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq) + } + if bz := req.PostFormValue("z"); bz != "post" { + t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz) + } + if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) { + t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs) + } + if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) { + t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both) + } + if prio := req.FormValue("prio"); prio != "2" { + t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio) + } + if empty := req.FormValue("empty"); empty != "" { + t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty) + } +} + type stringMap map[string][]string type parseContentTypeTest struct { shouldError bool @@ -123,7 +154,25 @@ func TestMultipartReader(t *testing.T) { req.Header = Header{"Content-Type": {"text/plain"}} multipart, err = req.MultipartReader() if multipart != nil { - t.Errorf("unexpected multipart for text/plain") + t.Error("unexpected multipart for text/plain") + } +} + +func TestParseMultipartForm(t *testing.T) { + req := &Request{ + Method: "POST", + Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}}, + Body: ioutil.NopCloser(new(bytes.Buffer)), + } + err := req.ParseMultipartForm(25) + if err == nil { + t.Error("expected multipart EOF, got nil") + } + + req.Header = Header{"Content-Type": {"text/plain"}} + err = req.ParseMultipartForm(25) + if err != ErrNotMultipart { + t.Error("expected ErrNotMultipart for text/plain") } } @@ -189,16 +238,38 @@ func TestMultipartRequestAuto(t *testing.T) { validateTestMultipartContents(t, req, true) } -func TestEmptyMultipartRequest(t *testing.T) { - // Test that FormValue and FormFile automatically invoke - // ParseMultipartForm and return the right values. - req, err := NewRequest("GET", "/", nil) - if err != nil { - t.Errorf("NewRequest err = %q", err) - } +func TestMissingFileMultipartRequest(t *testing.T) { + // Test that FormFile returns an error if + // the named file is missing. + req := newTestMultipartRequest(t) testMissingFile(t, req) } +// Test that FormValue invokes ParseMultipartForm. +func TestFormValueCallsParseMultipartForm(t *testing.T) { + req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post")) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") + if req.Form != nil { + t.Fatal("Unexpected request Form, want nil") + } + req.FormValue("z") + if req.Form == nil { + t.Fatal("ParseMultipartForm not called by FormValue") + } +} + +// Test that FormFile invokes ParseMultipartForm. +func TestFormFileCallsParseMultipartForm(t *testing.T) { + req := newTestMultipartRequest(t) + if req.Form != nil { + t.Fatal("Unexpected request Form, want nil") + } + req.FormFile("") + if req.Form == nil { + t.Fatal("ParseMultipartForm not called by FormFile") + } +} + // Test that ParseMultipartForm errors if called // after MultipartReader on the same request. func TestParseMultipartFormOrder(t *testing.T) { diff --git a/libgo/go/net/http/requestwrite_test.go b/libgo/go/net/http/requestwrite_test.go index 561eea28e5a..dc0e204cac9 100644 --- a/libgo/go/net/http/requestwrite_test.go +++ b/libgo/go/net/http/requestwrite_test.go @@ -310,6 +310,46 @@ var reqWriteTests = []reqWriteTest{ WantError: errors.New("http: Request.ContentLength=5 with nil Body"), }, + // Request with a 0 ContentLength and a body with 1 byte content and an error. + { + Req: Request{ + Method: "POST", + URL: mustParseURL("/"), + Host: "example.com", + ProtoMajor: 1, + ProtoMinor: 1, + ContentLength: 0, // as if unset by user + }, + + Body: func() io.ReadCloser { + err := errors.New("Custom reader error") + errReader := &errorReader{err} + return ioutil.NopCloser(io.MultiReader(strings.NewReader("x"), errReader)) + }, + + WantError: errors.New("Custom reader error"), + }, + + // Request with a 0 ContentLength and a body without content and an error. + { + Req: Request{ + Method: "POST", + URL: mustParseURL("/"), + Host: "example.com", + ProtoMajor: 1, + ProtoMinor: 1, + ContentLength: 0, // as if unset by user + }, + + Body: func() io.ReadCloser { + err := errors.New("Custom reader error") + errReader := &errorReader{err} + return ioutil.NopCloser(errReader) + }, + + WantError: errors.New("Custom reader error"), + }, + // Verify that DumpRequest preserves the HTTP version number, doesn't add a Host, // and doesn't add a User-Agent. { diff --git a/libgo/go/net/http/response.go b/libgo/go/net/http/response.go index 0b991c72ef0..5d2c39080e4 100644 --- a/libgo/go/net/http/response.go +++ b/libgo/go/net/http/response.go @@ -8,6 +8,8 @@ package http import ( "bufio" + "bytes" + "crypto/tls" "errors" "io" "net/textproto" @@ -45,7 +47,8 @@ type Response struct { // // The http Client and Transport guarantee that Body is always // non-nil, even on responses without a body or responses with - // a zero-lengthed body. + // a zero-length body. It is the caller's responsibility to + // close Body. // // The Body is automatically dechunked if the server replied // with a "chunked" Transfer-Encoding. @@ -74,6 +77,12 @@ type Response struct { // Request's Body is nil (having already been consumed). // This is only populated for Client requests. Request *Request + + // TLS contains information about the TLS connection on which the + // response was received. It is nil for unencrypted responses. + // The pointer is shared between responses and should not be + // modified. + TLS *tls.ConnectionState } // Cookies parses and returns the cookies set in the Set-Cookie headers. @@ -192,7 +201,6 @@ func (r *Response) ProtoAtLeast(major, minor int) bool { // // Body is closed after it is sent. func (r *Response) Write(w io.Writer) error { - // Status line text := r.Status if text == "" { @@ -205,10 +213,45 @@ func (r *Response) Write(w io.Writer) error { protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor) statusCode := strconv.Itoa(r.StatusCode) + " " text = strings.TrimPrefix(text, statusCode) - io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n") + if _, err := io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n"); err != nil { + return err + } + + // Clone it, so we can modify r1 as needed. + r1 := new(Response) + *r1 = *r + if r1.ContentLength == 0 && r1.Body != nil { + // Is it actually 0 length? Or just unknown? + var buf [1]byte + n, err := r1.Body.Read(buf[:]) + if err != nil && err != io.EOF { + return err + } + if n == 0 { + // Reset it to a known zero reader, in case underlying one + // is unhappy being read repeatedly. + r1.Body = eofReader + } else { + r1.ContentLength = -1 + r1.Body = struct { + io.Reader + io.Closer + }{ + io.MultiReader(bytes.NewReader(buf[:1]), r.Body), + r.Body, + } + } + } + // If we're sending a non-chunked HTTP/1.1 response without a + // content-length, the only way to do that is the old HTTP/1.0 + // way, by noting the EOF with a connection close, so we need + // to set Close. + if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) { + r1.Close = true + } // Process Body,ContentLength,Close,Trailer - tw, err := newTransferWriter(r) + tw, err := newTransferWriter(r1) if err != nil { return err } @@ -223,8 +266,19 @@ func (r *Response) Write(w io.Writer) error { return err } + // contentLengthAlreadySent may have been already sent for + // POST/PUT requests, even if zero length. See Issue 8180. + contentLengthAlreadySent := tw.shouldSendContentLength() + if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent { + if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil { + return err + } + } + // End-of-header - io.WriteString(w, "\r\n") + if _, err := io.WriteString(w, "\r\n"); err != nil { + return err + } // Write body and trailer err = tw.WriteBody(w) diff --git a/libgo/go/net/http/response_test.go b/libgo/go/net/http/response_test.go index d6e77b19c10..4b8946f7ae4 100644 --- a/libgo/go/net/http/response_test.go +++ b/libgo/go/net/http/response_test.go @@ -29,6 +29,10 @@ func dummyReq(method string) *Request { return &Request{Method: method} } +func dummyReq11(method string) *Request { + return &Request{Method: method, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1} +} + var respTests = []respTest{ // Unchunked response without Content-Length. { diff --git a/libgo/go/net/http/responsewrite_test.go b/libgo/go/net/http/responsewrite_test.go index 4799b4792b3..585b13b8504 100644 --- a/libgo/go/net/http/responsewrite_test.go +++ b/libgo/go/net/http/responsewrite_test.go @@ -26,7 +26,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 0, Request: dummyReq("GET"), Header: Header{}, - Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")), + Body: ioutil.NopCloser(strings.NewReader("abcdef")), ContentLength: 6, }, @@ -49,6 +49,106 @@ func TestResponseWrite(t *testing.T) { "\r\n" + "abcdef", }, + // HTTP/1.1 response with unknown length and Connection: close + { + Response{ + StatusCode: 200, + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq("GET"), + Header: Header{}, + Body: ioutil.NopCloser(strings.NewReader("abcdef")), + ContentLength: -1, + Close: true, + }, + "HTTP/1.1 200 OK\r\n" + + "Connection: close\r\n" + + "\r\n" + + "abcdef", + }, + // HTTP/1.1 response with unknown length and not setting connection: close + { + Response{ + StatusCode: 200, + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq11("GET"), + Header: Header{}, + Body: ioutil.NopCloser(strings.NewReader("abcdef")), + ContentLength: -1, + Close: false, + }, + "HTTP/1.1 200 OK\r\n" + + "Connection: close\r\n" + + "\r\n" + + "abcdef", + }, + // HTTP/1.1 response with unknown length and not setting connection: close, but + // setting chunked. + { + Response{ + StatusCode: 200, + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq11("GET"), + Header: Header{}, + Body: ioutil.NopCloser(strings.NewReader("abcdef")), + ContentLength: -1, + TransferEncoding: []string{"chunked"}, + Close: false, + }, + "HTTP/1.1 200 OK\r\n" + + "Transfer-Encoding: chunked\r\n\r\n" + + "6\r\nabcdef\r\n0\r\n\r\n", + }, + // HTTP/1.1 response 0 content-length, and nil body + { + Response{ + StatusCode: 200, + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq11("GET"), + Header: Header{}, + Body: nil, + ContentLength: 0, + Close: false, + }, + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n", + }, + // HTTP/1.1 response 0 content-length, and non-nil empty body + { + Response{ + StatusCode: 200, + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq11("GET"), + Header: Header{}, + Body: ioutil.NopCloser(strings.NewReader("")), + ContentLength: 0, + Close: false, + }, + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "\r\n", + }, + // HTTP/1.1 response 0 content-length, and non-nil non-empty body + { + Response{ + StatusCode: 200, + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq11("GET"), + Header: Header{}, + Body: ioutil.NopCloser(strings.NewReader("foo")), + ContentLength: 0, + Close: false, + }, + "HTTP/1.1 200 OK\r\n" + + "Connection: close\r\n" + + "\r\nfoo", + }, // HTTP/1.1, chunked coding; empty trailer; close { Response{ @@ -91,6 +191,22 @@ func TestResponseWrite(t *testing.T) { "Foo: Bar Baz\r\n" + "\r\n", }, + + // Want a single Content-Length header. Fixing issue 8180 where + // there were two. + { + Response{ + StatusCode: StatusOK, + ProtoMajor: 1, + ProtoMinor: 1, + Request: &Request{Method: "POST"}, + Header: Header{}, + ContentLength: 0, + TransferEncoding: nil, + Body: nil, + }, + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + }, } for i := range respWriteTests { diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index e7a3e6ea75f..8371dd82f58 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -851,7 +851,9 @@ func TestTLSHandshakeTimeout(t *testing.T) { } defer afterTest(t) ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) + errc := make(chanWriter, 10) // but only expecting 1 ts.Config.ReadTimeout = 250 * time.Millisecond + ts.Config.ErrorLog = log.New(errc, "", 0) ts.StartTLS() defer ts.Close() conn, err := net.Dial("tcp", ts.Listener.Addr().String()) @@ -866,6 +868,14 @@ func TestTLSHandshakeTimeout(t *testing.T) { t.Errorf("Read = %d, %v; want an error and no bytes", n, err) } }) + select { + case v := <-errc: + if !strings.Contains(v, "timeout") && !strings.Contains(v, "TLS handshake") { + t.Errorf("expected a TLS handshake timeout error; got %q", v) + } + case <-time.After(5 * time.Second): + t.Errorf("timeout waiting for logged error") + } } func TestTLSServer(t *testing.T) { @@ -878,6 +888,7 @@ func TestTLSServer(t *testing.T) { } } })) + ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) defer ts.Close() // Connect an idle TCP connection to this server before we run @@ -922,31 +933,50 @@ func TestTLSServer(t *testing.T) { } type serverExpectTest struct { - contentLength int // of request body + contentLength int // of request body + chunked bool expectation string // e.g. "100-continue" readBody bool // whether handler should read the body (if false, sends StatusUnauthorized) expectedResponse string // expected substring in first line of http response } +func expectTest(contentLength int, expectation string, readBody bool, expectedResponse string) serverExpectTest { + return serverExpectTest{ + contentLength: contentLength, + expectation: expectation, + readBody: readBody, + expectedResponse: expectedResponse, + } +} + var serverExpectTests = []serverExpectTest{ // Normal 100-continues, case-insensitive. - {100, "100-continue", true, "100 Continue"}, - {100, "100-cOntInUE", true, "100 Continue"}, + expectTest(100, "100-continue", true, "100 Continue"), + expectTest(100, "100-cOntInUE", true, "100 Continue"), // No 100-continue. - {100, "", true, "200 OK"}, + expectTest(100, "", true, "200 OK"), // 100-continue but requesting client to deny us, // so it never reads the body. - {100, "100-continue", false, "401 Unauthorized"}, + expectTest(100, "100-continue", false, "401 Unauthorized"), // Likewise without 100-continue: - {100, "", false, "401 Unauthorized"}, + expectTest(100, "", false, "401 Unauthorized"), // Non-standard expectations are failures - {0, "a-pony", false, "417 Expectation Failed"}, + expectTest(0, "a-pony", false, "417 Expectation Failed"), - // Expect-100 requested but no body - {0, "100-continue", true, "400 Bad Request"}, + // Expect-100 requested but no body (is apparently okay: Issue 7625) + expectTest(0, "100-continue", true, "200 OK"), + // Expect-100 requested but handler doesn't read the body + expectTest(0, "100-continue", false, "401 Unauthorized"), + // Expect-100 continue with no body, but a chunked body. + { + expectation: "100-continue", + readBody: true, + chunked: true, + expectedResponse: "100 Continue", + }, } // Tests that the server responds to the "Expect" request header @@ -975,21 +1005,38 @@ func TestServerExpect(t *testing.T) { // Only send the body immediately if we're acting like an HTTP client // that doesn't send 100-continue expectations. - writeBody := test.contentLength > 0 && strings.ToLower(test.expectation) != "100-continue" + writeBody := test.contentLength != 0 && strings.ToLower(test.expectation) != "100-continue" go func() { + contentLen := fmt.Sprintf("Content-Length: %d", test.contentLength) + if test.chunked { + contentLen = "Transfer-Encoding: chunked" + } _, err := fmt.Fprintf(conn, "POST /?readbody=%v HTTP/1.1\r\n"+ "Connection: close\r\n"+ - "Content-Length: %d\r\n"+ + "%s\r\n"+ "Expect: %s\r\nHost: foo\r\n\r\n", - test.readBody, test.contentLength, test.expectation) + test.readBody, contentLen, test.expectation) if err != nil { t.Errorf("On test %#v, error writing request headers: %v", test, err) return } if writeBody { + var targ io.WriteCloser = struct { + io.Writer + io.Closer + }{ + conn, + ioutil.NopCloser(nil), + } + if test.chunked { + targ = httputil.NewChunkedWriter(conn) + } body := strings.Repeat("A", test.contentLength) - _, err = fmt.Fprint(conn, body) + _, err = fmt.Fprint(targ, body) + if err == nil { + err = targ.Close() + } if err != nil { if !test.readBody { // Server likely already hung up on us. @@ -2097,7 +2144,7 @@ func TestCodesPreventingContentTypeAndBody(t *testing.T) { got := ht.rawResponse(req) wantStatus := fmt.Sprintf("%d %s", code, StatusText(code)) if !strings.Contains(got, wantStatus) { - t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, req, got) + t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got) } else if strings.Contains(got, "Content-Length") { t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got) } else if strings.Contains(got, "stuff") { @@ -2107,6 +2154,21 @@ func TestCodesPreventingContentTypeAndBody(t *testing.T) { } } +func TestContentTypeOkayOn204(t *testing.T) { + ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Content-Length", "123") // suppressed + w.Header().Set("Content-Type", "foo/bar") + w.WriteHeader(204) + })) + got := ht.rawResponse("GET / HTTP/1.1") + if !strings.Contains(got, "Content-Type: foo/bar") { + t.Errorf("Response = %q; want Content-Type: foo/bar", got) + } + if strings.Contains(got, "Content-Length: 123") { + t.Errorf("Response = %q; don't want a Content-Length", got) + } +} + // Issue 6995 // A server Handler can receive a Request, and then turn around and // give a copy of that Request.Body out to the Transport (e.g. any @@ -2225,8 +2287,8 @@ func TestResponseWriterWriteStringAllocs(t *testing.T) { w.Write([]byte("Hello world")) } })) - before := testing.AllocsPerRun(25, func() { ht.rawResponse("GET / HTTP/1.0") }) - after := testing.AllocsPerRun(25, func() { ht.rawResponse("GET /s HTTP/1.0") }) + before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") }) + after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") }) if int(after) >= int(before) { t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before) } @@ -2245,6 +2307,230 @@ func TestAppendTime(t *testing.T) { } } +func TestServerConnState(t *testing.T) { + defer afterTest(t) + handler := map[string]func(w ResponseWriter, r *Request){ + "/": func(w ResponseWriter, r *Request) { + fmt.Fprintf(w, "Hello.") + }, + "/close": func(w ResponseWriter, r *Request) { + w.Header().Set("Connection", "close") + fmt.Fprintf(w, "Hello.") + }, + "/hijack": func(w ResponseWriter, r *Request) { + c, _, _ := w.(Hijacker).Hijack() + c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello.")) + c.Close() + }, + "/hijack-panic": func(w ResponseWriter, r *Request) { + c, _, _ := w.(Hijacker).Hijack() + c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello.")) + c.Close() + panic("intentional panic") + }, + } + ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { + handler[r.URL.Path](w, r) + })) + defer ts.Close() + + var mu sync.Mutex // guard stateLog and connID + var stateLog = map[int][]ConnState{} + var connID = map[net.Conn]int{} + + ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + ts.Config.ConnState = func(c net.Conn, state ConnState) { + if c == nil { + t.Errorf("nil conn seen in state %s", state) + return + } + mu.Lock() + defer mu.Unlock() + id, ok := connID[c] + if !ok { + id = len(connID) + 1 + connID[c] = id + } + stateLog[id] = append(stateLog[id], state) + } + ts.Start() + + mustGet(t, ts.URL+"/") + mustGet(t, ts.URL+"/close") + + mustGet(t, ts.URL+"/") + mustGet(t, ts.URL+"/", "Connection", "close") + + mustGet(t, ts.URL+"/hijack") + mustGet(t, ts.URL+"/hijack-panic") + + // New->Closed + { + c, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + c.Close() + } + + // New->Active->Closed + { + c, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + if _, err := io.WriteString(c, "BOGUS REQUEST\r\n\r\n"); err != nil { + t.Fatal(err) + } + c.Close() + } + + // New->Idle->Closed + { + c, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil { + t.Fatal(err) + } + res, err := ReadResponse(bufio.NewReader(c), nil) + if err != nil { + t.Fatal(err) + } + if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + t.Fatal(err) + } + c.Close() + } + + want := map[int][]ConnState{ + 1: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed}, + 2: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed}, + 3: []ConnState{StateNew, StateActive, StateHijacked}, + 4: []ConnState{StateNew, StateActive, StateHijacked}, + 5: []ConnState{StateNew, StateClosed}, + 6: []ConnState{StateNew, StateActive, StateClosed}, + 7: []ConnState{StateNew, StateActive, StateIdle, StateClosed}, + } + logString := func(m map[int][]ConnState) string { + var b bytes.Buffer + for id, l := range m { + fmt.Fprintf(&b, "Conn %d: ", id) + for _, s := range l { + fmt.Fprintf(&b, "%s ", s) + } + b.WriteString("\n") + } + return b.String() + } + + for i := 0; i < 5; i++ { + time.Sleep(time.Duration(i) * 50 * time.Millisecond) + mu.Lock() + match := reflect.DeepEqual(stateLog, want) + mu.Unlock() + if match { + return + } + } + + mu.Lock() + t.Errorf("Unexpected events.\nGot log: %s\n Want: %s\n", logString(stateLog), logString(want)) + mu.Unlock() +} + +func mustGet(t *testing.T, url string, headers ...string) { + req, err := NewRequest("GET", url, nil) + if err != nil { + t.Fatal(err) + } + for len(headers) > 0 { + req.Header.Add(headers[0], headers[1]) + headers = headers[2:] + } + res, err := DefaultClient.Do(req) + if err != nil { + t.Errorf("Error fetching %s: %v", url, err) + return + } + _, err = ioutil.ReadAll(res.Body) + defer res.Body.Close() + if err != nil { + t.Errorf("Error reading %s: %v", url, err) + } +} + +func TestServerKeepAlivesEnabled(t *testing.T) { + defer afterTest(t) + ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) + ts.Config.SetKeepAlivesEnabled(false) + ts.Start() + defer ts.Close() + res, err := Get(ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + if !res.Close { + t.Errorf("Body.Close == false; want true") + } +} + +// golang.org/issue/7856 +func TestServerEmptyBodyRace(t *testing.T) { + defer afterTest(t) + var n int32 + ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { + atomic.AddInt32(&n, 1) + })) + defer ts.Close() + var wg sync.WaitGroup + const reqs = 20 + for i := 0; i < reqs; i++ { + wg.Add(1) + go func() { + defer wg.Done() + res, err := Get(ts.URL) + if err != nil { + t.Error(err) + return + } + defer res.Body.Close() + _, err = io.Copy(ioutil.Discard, res.Body) + if err != nil { + t.Error(err) + return + } + }() + } + wg.Wait() + if got := atomic.LoadInt32(&n); got != reqs { + t.Errorf("handler ran %d times; want %d", got, reqs) + } +} + +func TestServerConnStateNew(t *testing.T) { + sawNew := false // if the test is buggy, we'll race on this variable. + srv := &Server{ + ConnState: func(c net.Conn, state ConnState) { + if state == StateNew { + sawNew = true // testing that this write isn't racy + } + }, + Handler: HandlerFunc(func(w ResponseWriter, r *Request) {}), // irrelevant + } + srv.Serve(&oneConnListener{ + conn: &rwTestConn{ + Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"), + Writer: ioutil.Discard, + }, + }) + if !sawNew { // testing that this read isn't racy + t.Error("StateNew not seen") + } +} + func BenchmarkClientServer(b *testing.B) { b.ReportAllocs() b.StopTimer() @@ -2259,7 +2545,6 @@ func BenchmarkClientServer(b *testing.B) { if err != nil { b.Fatal("Get:", err) } - defer res.Body.Close() all, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { @@ -2282,42 +2567,33 @@ func BenchmarkClientServerParallel64(b *testing.B) { benchmarkClientServerParallel(b, 64) } -func benchmarkClientServerParallel(b *testing.B, conc int) { +func benchmarkClientServerParallel(b *testing.B, parallelism int) { b.ReportAllocs() - b.StopTimer() ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) { fmt.Fprintf(rw, "Hello world.\n") })) defer ts.Close() - b.StartTimer() - - numProcs := runtime.GOMAXPROCS(-1) * conc - var wg sync.WaitGroup - wg.Add(numProcs) - n := int32(b.N) - for p := 0; p < numProcs; p++ { - go func() { - for atomic.AddInt32(&n, -1) >= 0 { - res, err := Get(ts.URL) - if err != nil { - b.Logf("Get: %v", err) - continue - } - all, err := ioutil.ReadAll(res.Body) - res.Body.Close() - if err != nil { - b.Logf("ReadAll: %v", err) - continue - } - body := string(all) - if body != "Hello world.\n" { - panic("Got body: " + body) - } + b.ResetTimer() + b.SetParallelism(parallelism) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + res, err := Get(ts.URL) + if err != nil { + b.Logf("Get: %v", err) + continue } - wg.Done() - }() - } - wg.Wait() + all, err := ioutil.ReadAll(res.Body) + res.Body.Close() + if err != nil { + b.Logf("ReadAll: %v", err) + continue + } + body := string(all) + if body != "Hello world.\n" { + panic("Got body: " + body) + } + } + }) } // A benchmark for profiling the server without the HTTP client code. diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go index fea1898fd7e..eae097eb8e9 100644 --- a/libgo/go/net/http/server.go +++ b/libgo/go/net/http/server.go @@ -22,6 +22,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" ) @@ -138,6 +139,7 @@ func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { buf = c.buf c.rwc = nil c.buf = nil + c.setState(rwc, StateHijacked) return } @@ -496,6 +498,10 @@ func (srv *Server) maxHeaderBytes() int { return DefaultMaxHeaderBytes } +func (srv *Server) initialLimitedReaderSize() int64 { + return int64(srv.maxHeaderBytes()) + 4096 // bufio slop +} + // wrapper around io.ReaderCloser which on first read, sends an // HTTP/1.1 100 Continue header type expectContinueReader struct { @@ -566,7 +572,7 @@ func (c *conn) readRequest() (w *response, err error) { }() } - c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */ + c.lr.N = c.server.initialLimitedReaderSize() var req *Request if req, err = ReadRequest(c.buf.Reader); err != nil { if c.lr.N == 0 { @@ -614,11 +620,11 @@ const maxPostHandlerReadBytes = 256 << 10 func (w *response) WriteHeader(code int) { if w.conn.hijacked() { - log.Print("http: response.WriteHeader on hijacked connection") + w.conn.server.logf("http: response.WriteHeader on hijacked connection") return } if w.wroteHeader { - log.Print("http: multiple response.WriteHeader calls") + w.conn.server.logf("http: multiple response.WriteHeader calls") return } w.wroteHeader = true @@ -633,7 +639,7 @@ func (w *response) WriteHeader(code int) { if err == nil && v >= 0 { w.contentLength = v } else { - log.Printf("http: invalid Content-Length of %q", cl) + w.conn.server.logf("http: invalid Content-Length of %q", cl) w.handlerHeader.Del("Content-Length") } } @@ -703,6 +709,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { cw.wroteHeader = true w := cw.res + keepAlivesEnabled := w.conn.server.doKeepAlives() isHEAD := w.req.Method == "HEAD" // header is written out to w.conn.buf below. Depending on the @@ -750,7 +757,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { // If this was an HTTP/1.0 request with keep-alive and we sent a // Content-Length back, we can make this a keep-alive response ... - if w.req.wantsHttp10KeepAlive() { + if w.req.wantsHttp10KeepAlive() && keepAlivesEnabled { sentLength := header.get("Content-Length") != "" if sentLength && header.get("Connection") == "keep-alive" { w.closeAfterReply = false @@ -769,7 +776,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { w.closeAfterReply = true } - if header.get("Connection") == "close" { + if header.get("Connection") == "close" || !keepAlivesEnabled { w.closeAfterReply = true } @@ -792,18 +799,16 @@ func (cw *chunkWriter) writeHeader(p []byte) { } code := w.status - if !bodyAllowedForStatus(code) { - // Must not have body. - // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers" - for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} { - delHeader(k) - } - } else { + if bodyAllowedForStatus(code) { // If no content type, apply sniffing algorithm to body. _, haveType := header["Content-Type"] if !haveType { setHeader.contentType = DetectContentType(p) } + } else { + for _, k := range suppressedHeaders(code) { + delHeader(k) + } } if _, ok := header["Date"]; !ok { @@ -815,7 +820,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { if hasCL && hasTE && te != "identity" { // TODO: return an error if WriteHeader gets a return parameter // For now just ignore the Content-Length. - log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d", + w.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d", te, w.contentLength) delHeader("Content-Length") hasCL = false @@ -851,7 +856,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { return } - if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") { + if w.closeAfterReply && (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) { delHeader("Connection") if w.req.ProtoAtLeast(1, 1) { setHeader.connection = "close" @@ -961,7 +966,7 @@ func (w *response) WriteString(data string) (n int, err error) { // either dataB or dataS is non-zero. func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) { if w.conn.hijacked() { - log.Print("http: response.Write on hijacked connection") + w.conn.server.logf("http: response.Write on hijacked connection") return 0, ErrHijacked } if !w.wroteHeader { @@ -1079,17 +1084,25 @@ func validNPN(proto string) bool { return true } +func (c *conn) setState(nc net.Conn, state ConnState) { + if hook := c.server.ConnState; hook != nil { + hook(nc, state) + } +} + // Serve a new connection. func (c *conn) serve() { + origConn := c.rwc // copy it before it's set nil on Close or Hijack defer func() { if err := recover(); err != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] - log.Printf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) + c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) } if !c.hijacked() { c.close() + c.setState(origConn, StateClosed) } }() @@ -1101,6 +1114,7 @@ func (c *conn) serve() { c.rwc.SetWriteDeadline(time.Now().Add(d)) } if err := tlsConn.Handshake(); err != nil { + c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) return } c.tlsState = new(tls.ConnectionState) @@ -1116,6 +1130,10 @@ func (c *conn) serve() { for { w, err := c.readRequest() + if c.lr.N != c.server.initialLimitedReaderSize() { + // If we read any bytes off the wire, we're active. + c.setState(c.rwc, StateActive) + } if err != nil { if err == errTooLarge { // Their HTTP client may or may not be @@ -1138,16 +1156,10 @@ func (c *conn) serve() { // Expect 100 Continue support req := w.req if req.expectsContinue() { - if req.ProtoAtLeast(1, 1) { + if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 { // Wrap the Body reader with one that replies on the connection req.Body = &expectContinueReader{readCloser: req.Body, resp: w} } - if req.ContentLength == 0 { - w.Header().Set("Connection", "close") - w.WriteHeader(StatusBadRequest) - w.finishRequest() - break - } req.Header.Del("Expect") } else if req.Header.get("Expect") != "" { w.sendExpectationFailed() @@ -1170,6 +1182,7 @@ func (c *conn) serve() { } break } + c.setState(c.rwc, StateIdle) } } @@ -1564,6 +1577,7 @@ func Serve(l net.Listener, handler Handler) error { } // A Server defines parameters for running an HTTP server. +// The zero value for Server is a valid configuration. type Server struct { Addr string // TCP address to listen on, ":http" if empty Handler Handler // handler to invoke, http.DefaultServeMux if nil @@ -1580,6 +1594,66 @@ type Server struct { // and RemoteAddr if not already set. The connection is // automatically closed when the function returns. TLSNextProto map[string]func(*Server, *tls.Conn, Handler) + + // ConnState specifies an optional callback function that is + // called when a client connection changes state. See the + // ConnState type and associated constants for details. + ConnState func(net.Conn, ConnState) + + // ErrorLog specifies an optional logger for errors accepting + // connections and unexpected behavior from handlers. + // If nil, logging goes to os.Stderr via the log package's + // standard logger. + ErrorLog *log.Logger + + disableKeepAlives int32 // accessed atomically. +} + +// A ConnState represents the state of a client connection to a server. +// It's used by the optional Server.ConnState hook. +type ConnState int + +const ( + // StateNew represents a new connection that is expected to + // send a request immediately. Connections begin at this + // state and then transition to either StateActive or + // StateClosed. + StateNew ConnState = iota + + // StateActive represents a connection that has read 1 or more + // bytes of a request. The Server.ConnState hook for + // StateActive fires before the request has entered a handler + // and doesn't fire again until the request has been + // handled. After the request is handled, the state + // transitions to StateClosed, StateHijacked, or StateIdle. + StateActive + + // StateIdle represents a connection that has finished + // handling a request and is in the keep-alive state, waiting + // for a new request. Connections transition from StateIdle + // to either StateActive or StateClosed. + StateIdle + + // StateHijacked represents a hijacked connection. + // This is a terminal state. It does not transition to StateClosed. + StateHijacked + + // StateClosed represents a closed connection. + // This is a terminal state. Hijacked connections do not + // transition to StateClosed. + StateClosed +) + +var stateName = map[ConnState]string{ + StateNew: "new", + StateActive: "active", + StateIdle: "idle", + StateHijacked: "hijacked", + StateClosed: "closed", +} + +func (c ConnState) String() string { + return stateName[c] } // serverHandler delegates to either the server's Handler or @@ -1632,7 +1706,7 @@ func (srv *Server) Serve(l net.Listener) error { if max := 1 * time.Second; tempDelay > max { tempDelay = max } - log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) + srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } @@ -1643,10 +1717,35 @@ func (srv *Server) Serve(l net.Listener) error { if err != nil { continue } + c.setState(c.rwc, StateNew) // before Serve can return go c.serve() } } +func (s *Server) doKeepAlives() bool { + return atomic.LoadInt32(&s.disableKeepAlives) == 0 +} + +// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. +// By default, keep-alives are always enabled. Only very +// resource-constrained environments or servers in the process of +// shutting down should disable them. +func (s *Server) SetKeepAlivesEnabled(v bool) { + if v { + atomic.StoreInt32(&s.disableKeepAlives, 0) + } else { + atomic.StoreInt32(&s.disableKeepAlives, 1) + } +} + +func (s *Server) logf(format string, args ...interface{}) { + if s.ErrorLog != nil { + s.ErrorLog.Printf(format, args...) + } else { + log.Printf(format, args...) + } +} + // ListenAndServe listens on the TCP network address addr // and then calls Serve with handler to handle requests // on incoming connections. Handler is typically nil, @@ -1870,17 +1969,24 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) { } } +type eofReaderWithWriteTo struct{} + +func (eofReaderWithWriteTo) WriteTo(io.Writer) (int64, error) { return 0, nil } +func (eofReaderWithWriteTo) Read([]byte) (int, error) { return 0, io.EOF } + // eofReader is a non-nil io.ReadCloser that always returns EOF. -// It embeds a *strings.Reader so it still has a WriteTo method -// and io.Copy won't need a buffer. +// It has a WriteTo method so io.Copy won't need a buffer. var eofReader = &struct { - *strings.Reader + eofReaderWithWriteTo io.Closer }{ - strings.NewReader(""), + eofReaderWithWriteTo{}, ioutil.NopCloser(nil), } +// Verify that an io.Copy from an eofReader won't require a buffer. +var _ io.WriterTo = eofReader + // initNPNRequest is an HTTP handler that initializes certain // uninitialized fields in its *Request. Such partially-initialized // Requests come from NPN protocol handlers. diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go index 2eec9d9abc4..7f63686528a 100644 --- a/libgo/go/net/http/transfer.go +++ b/libgo/go/net/http/transfer.go @@ -12,11 +12,20 @@ import ( "io" "io/ioutil" "net/textproto" + "sort" "strconv" "strings" "sync" ) +type errorReader struct { + err error +} + +func (r *errorReader) Read(p []byte) (n int, err error) { + return 0, r.err +} + // transferWriter inspects the fields of a user-supplied Request or Response, // sanitizes them without changing the user object and provides methods for // writing the respective header, body and trailer in wire format. @@ -53,8 +62,11 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { if t.ContentLength == 0 { // Test to see if it's actually zero or just unset. var buf [1]byte - n, _ := io.ReadFull(t.Body, buf[:]) - if n == 1 { + n, rerr := io.ReadFull(t.Body, buf[:]) + if rerr != nil && rerr != io.EOF { + t.ContentLength = -1 + t.Body = &errorReader{rerr} + } else if n == 1 { // Oh, guess there is data in this Body Reader after all. // The ContentLength field just wasn't set. // Stich the Body back together again, re-attaching our @@ -132,11 +144,10 @@ func (t *transferWriter) shouldSendContentLength() bool { return false } -func (t *transferWriter) WriteHeader(w io.Writer) (err error) { +func (t *transferWriter) WriteHeader(w io.Writer) error { if t.Close { - _, err = io.WriteString(w, "Connection: close\r\n") - if err != nil { - return + if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil { + return err } } @@ -144,43 +155,44 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err error) { // function of the sanitized field triple (Body, ContentLength, // TransferEncoding) if t.shouldSendContentLength() { - io.WriteString(w, "Content-Length: ") - _, err = io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n") - if err != nil { - return + if _, err := io.WriteString(w, "Content-Length: "); err != nil { + return err + } + if _, err := io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n"); err != nil { + return err } } else if chunked(t.TransferEncoding) { - _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n") - if err != nil { - return + if _, err := io.WriteString(w, "Transfer-Encoding: chunked\r\n"); err != nil { + return err } } // Write Trailer header if t.Trailer != nil { - // TODO: At some point, there should be a generic mechanism for - // writing long headers, using HTTP line splitting - io.WriteString(w, "Trailer: ") - needComma := false + keys := make([]string, 0, len(t.Trailer)) for k := range t.Trailer { k = CanonicalHeaderKey(k) switch k { case "Transfer-Encoding", "Trailer", "Content-Length": return &badStringError{"invalid Trailer key", k} } - if needComma { - io.WriteString(w, ",") + keys = append(keys, k) + } + if len(keys) > 0 { + sort.Strings(keys) + // TODO: could do better allocation-wise here, but trailers are rare, + // so being lazy for now. + if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil { + return err } - io.WriteString(w, k) - needComma = true } - _, err = io.WriteString(w, "\r\n") } - return + return nil } -func (t *transferWriter) WriteBody(w io.Writer) (err error) { +func (t *transferWriter) WriteBody(w io.Writer) error { + var err error var ncopy int64 // Write body @@ -217,11 +229,16 @@ func (t *transferWriter) WriteBody(w io.Writer) (err error) { // TODO(petar): Place trailer writer code here. if chunked(t.TransferEncoding) { + // Write Trailer header + if t.Trailer != nil { + if err := t.Trailer.Write(w); err != nil { + return err + } + } // Last chunk, empty trailer _, err = io.WriteString(w, "\r\n") } - - return + return err } type transferReader struct { @@ -253,6 +270,22 @@ func bodyAllowedForStatus(status int) bool { return true } +var ( + suppressedHeaders304 = []string{"Content-Type", "Content-Length", "Transfer-Encoding"} + suppressedHeadersNoBody = []string{"Content-Length", "Transfer-Encoding"} +) + +func suppressedHeaders(status int) []string { + switch { + case status == 304: + // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers" + return suppressedHeaders304 + case !bodyAllowedForStatus(status): + return suppressedHeadersNoBody + } + return nil +} + // msg is *Request or *Response. func readTransfer(msg interface{}, r *bufio.Reader) (err error) { t := &transferReader{RequestMethod: "GET"} @@ -499,7 +532,7 @@ func fixTrailer(header Header, te []string) (Header, error) { case "Transfer-Encoding", "Trailer", "Content-Length": return nil, &badStringError{"bad trailer key", key} } - trailer.Del(key) + trailer[key] = nil } if len(trailer) == 0 { return nil, nil @@ -631,13 +664,23 @@ func (b *body) readTrailer() error { } switch rr := b.hdr.(type) { case *Request: - rr.Trailer = Header(hdr) + mergeSetHeader(&rr.Trailer, Header(hdr)) case *Response: - rr.Trailer = Header(hdr) + mergeSetHeader(&rr.Trailer, Header(hdr)) } return nil } +func mergeSetHeader(dst *Header, src Header) { + if *dst == nil { + *dst = src + return + } + for k, vv := range src { + (*dst)[k] = vv + } +} + func (b *body) Close() error { b.mu.Lock() defer b.mu.Unlock() diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index 2c312a77a02..b1cc632a782 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -30,7 +30,14 @@ import ( // and caches them for reuse by subsequent calls. It uses HTTP proxies // as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and // $no_proxy) environment variables. -var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment} +var DefaultTransport RoundTripper = &Transport{ + Proxy: ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, +} // DefaultMaxIdleConnsPerHost is the default value of Transport's // MaxIdleConnsPerHost. @@ -40,13 +47,13 @@ const DefaultMaxIdleConnsPerHost = 2 // https, and http proxies (for either http or https with CONNECT). // Transport can also cache connections for future re-use. type Transport struct { - idleMu sync.Mutex - idleConn map[connectMethodKey][]*persistConn - idleConnCh map[connectMethodKey]chan *persistConn - reqMu sync.Mutex - reqConn map[*Request]*persistConn - altMu sync.RWMutex - altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper + idleMu sync.Mutex + idleConn map[connectMethodKey][]*persistConn + idleConnCh map[connectMethodKey]chan *persistConn + reqMu sync.Mutex + reqCanceler map[*Request]func() + altMu sync.RWMutex + altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the @@ -63,6 +70,10 @@ type Transport struct { // tls.Client. If nil, the default configuration is used. TLSClientConfig *tls.Config + // TLSHandshakeTimeout specifies the maximum amount of time waiting to + // wait for a TLS handshake. Zero means no timeout. + TLSHandshakeTimeout time.Duration + // DisableKeepAlives, if true, prevents re-use of TCP connections // between different HTTP requests. DisableKeepAlives bool @@ -98,6 +109,9 @@ type Transport struct { // An error is returned if the proxy environment is invalid. // A nil URL and nil error are returned if no proxy is defined in the // environment, or a proxy should not be used for the given request. +// +// As a special case, if req.URL.Host is "localhost" (with or without +// a port number), then a nil URL and nil error will be returned. func ProxyFromEnvironment(req *Request) (*url.URL, error) { proxy := httpProxyEnv.Get() if proxy == "" { @@ -149,9 +163,11 @@ func (tr *transportRequest) extraHeaders() Header { // and redirects), see Get, Post, and the Client type. func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) { if req.URL == nil { + req.closeBody() return nil, errors.New("http: nil Request.URL") } if req.Header == nil { + req.closeBody() return nil, errors.New("http: nil Request.Header") } if req.URL.Scheme != "http" && req.URL.Scheme != "https" { @@ -162,16 +178,19 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) { } t.altMu.RUnlock() if rt == nil { + req.closeBody() return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme} } return rt.RoundTrip(req) } if req.URL.Host == "" { + req.closeBody() return nil, errors.New("http: no Host in request URL") } treq := &transportRequest{Request: req} cm, err := t.connectMethodForRequest(treq) if err != nil { + req.closeBody() return nil, err } @@ -179,8 +198,10 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) { // host (for http or https), the http proxy, or the http proxy // pre-CONNECTed to https server. In any case, we'll be ready // to send it requests. - pconn, err := t.getConn(cm) + pconn, err := t.getConn(req, cm) if err != nil { + t.setReqCanceler(req, nil) + req.closeBody() return nil, err } @@ -218,9 +239,6 @@ func (t *Transport) CloseIdleConnections() { t.idleConn = nil t.idleConnCh = nil t.idleMu.Unlock() - if m == nil { - return - } for _, conns := range m { for _, pconn := range conns { pconn.close() @@ -232,10 +250,10 @@ func (t *Transport) CloseIdleConnections() { // connection. func (t *Transport) CancelRequest(req *Request) { t.reqMu.Lock() - pc := t.reqConn[req] + cancel := t.reqCanceler[req] t.reqMu.Unlock() - if pc != nil { - pc.conn.Close() + if cancel != nil { + cancel() } } @@ -406,16 +424,16 @@ func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn) { } } -func (t *Transport) setReqConn(r *Request, pc *persistConn) { +func (t *Transport) setReqCanceler(r *Request, fn func()) { t.reqMu.Lock() defer t.reqMu.Unlock() - if t.reqConn == nil { - t.reqConn = make(map[*Request]*persistConn) + if t.reqCanceler == nil { + t.reqCanceler = make(map[*Request]func()) } - if pc != nil { - t.reqConn[r] = pc + if fn != nil { + t.reqCanceler[r] = fn } else { - delete(t.reqConn, r) + delete(t.reqCanceler, r) } } @@ -430,7 +448,7 @@ func (t *Transport) dial(network, addr string) (c net.Conn, err error) { // specified in the connectMethod. This includes doing a proxy CONNECT // and/or setting up TLS. If this doesn't return an error, the persistConn // is ready to write requests to. -func (t *Transport) getConn(cm connectMethod) (*persistConn, error) { +func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) { if pc := t.getIdleConn(cm); pc != nil { return pc, nil } @@ -440,6 +458,16 @@ func (t *Transport) getConn(cm connectMethod) (*persistConn, error) { err error } dialc := make(chan dialRes) + + handlePendingDial := func() { + if v := <-dialc; v.err == nil { + t.putIdleConn(v.pc) + } + } + + cancelc := make(chan struct{}) + t.setReqCanceler(req, func() { close(cancelc) }) + go func() { pc, err := t.dialConn(cm) dialc <- dialRes{pc, err} @@ -456,12 +484,11 @@ func (t *Transport) getConn(cm connectMethod) (*persistConn, error) { // else's dial that they didn't use. // But our dial is still going, so give it away // when it finishes: - go func() { - if v := <-dialc; v.err == nil { - t.putIdleConn(v.pc) - } - }() + go handlePendingDial() return pc, nil + case <-cancelc: + go handlePendingDial() + return nil, errors.New("net/http: request canceled while waiting for connection") } } @@ -477,12 +504,13 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) { pa := cm.proxyAuth() pconn := &persistConn{ - t: t, - cacheKey: cm.key(), - conn: conn, - reqch: make(chan requestAndChan, 50), - writech: make(chan writeRequest, 50), - closech: make(chan struct{}), + t: t, + cacheKey: cm.key(), + conn: conn, + reqch: make(chan requestAndChan, 1), + writech: make(chan writeRequest, 1), + closech: make(chan struct{}), + writeErrCh: make(chan error, 1), } switch { @@ -536,19 +564,38 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) { cfg = &clone } } - conn = tls.Client(conn, cfg) - if err = conn.(*tls.Conn).Handshake(); err != nil { + plainConn := conn + tlsConn := tls.Client(plainConn, cfg) + errc := make(chan error, 2) + var timer *time.Timer // for canceling TLS handshake + if d := t.TLSHandshakeTimeout; d != 0 { + timer = time.AfterFunc(d, func() { + errc <- tlsHandshakeTimeoutError{} + }) + } + go func() { + err := tlsConn.Handshake() + if timer != nil { + timer.Stop() + } + errc <- err + }() + if err := <-errc; err != nil { + plainConn.Close() return nil, err } if !cfg.InsecureSkipVerify { - if err = conn.(*tls.Conn).VerifyHostname(cfg.ServerName); err != nil { + if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { + plainConn.Close() return nil, err } } - pconn.conn = conn + cs := tlsConn.ConnectionState() + pconn.tlsState = &cs + pconn.conn = tlsConn } - pconn.br = bufio.NewReader(pconn.conn) + pconn.br = bufio.NewReader(noteEOFReader{pconn.conn, &pconn.sawEOF}) pconn.bw = bufio.NewWriter(pconn.conn) go pconn.readLoop() go pconn.writeLoop() @@ -615,8 +662,8 @@ func useProxy(addr string) bool { // // Cache key form Description // ----------------- ------------------------- -// ||http|foo.com http directly to server, no proxy -// ||https|foo.com https directly to server, no proxy +// |http|foo.com http directly to server, no proxy +// |https|foo.com https directly to server, no proxy // http://proxy.com|https|foo.com http to proxy, then CONNECT to foo.com // http://proxy.com|http http to proxy, http to anywhere after that // @@ -680,16 +727,23 @@ type persistConn struct { t *Transport cacheKey connectMethodKey conn net.Conn - closed bool // whether conn has been closed + tlsState *tls.ConnectionState br *bufio.Reader // from conn + sawEOF bool // whether we've seen EOF from conn; owned by readLoop bw *bufio.Writer // to conn reqch chan requestAndChan // written by roundTrip; read by readLoop writech chan writeRequest // written by roundTrip; read by writeLoop - closech chan struct{} // broadcast close when readLoop (TCP connection) closes + closech chan struct{} // closed when conn closed isProxy bool + // writeErrCh passes the request write error (usually nil) + // from the writeLoop goroutine to the readLoop which passes + // it off to the res.Body reader, which then uses it to decide + // whether or not a connection can be reused. Issue 7569. + writeErrCh chan error - lk sync.Mutex // guards following 3 fields + lk sync.Mutex // guards following fields numExpectedResponses int + closed bool // whether conn has been closed broken bool // an error has happened on this connection; marked broken so it's not reused. // mutateHeaderFunc is an optional func to modify extra // headers on each outbound request before it's written. (the @@ -697,6 +751,7 @@ type persistConn struct { mutateHeaderFunc func(Header) } +// isBroken reports whether this connection is in a known broken state. func (pc *persistConn) isBroken() bool { pc.lk.Lock() b := pc.broken @@ -704,6 +759,10 @@ func (pc *persistConn) isBroken() bool { return b } +func (pc *persistConn) cancelRequest() { + pc.conn.Close() +} + var remoteSideClosedFunc func(error) bool // or nil to use default func remoteSideClosed(err error) bool { @@ -717,7 +776,6 @@ func remoteSideClosed(err error) bool { } func (pc *persistConn) readLoop() { - defer close(pc.closech) alive := true for alive { @@ -725,12 +783,14 @@ func (pc *persistConn) readLoop() { pc.lk.Lock() if pc.numExpectedResponses == 0 { - pc.closeLocked() - pc.lk.Unlock() - if len(pb) > 0 { - log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v", - string(pb), err) + if !pc.closed { + pc.closeLocked() + if len(pb) > 0 { + log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v", + string(pb), err) + } } + pc.lk.Unlock() return } pc.lk.Unlock() @@ -749,6 +809,11 @@ func (pc *persistConn) readLoop() { resp, err = ReadResponse(pc.br, rc.req) } } + + if resp != nil { + resp.TLS = pc.tlsState + } + hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0 if err != nil { @@ -758,13 +823,7 @@ func (pc *persistConn) readLoop() { resp.Header.Del("Content-Encoding") resp.Header.Del("Content-Length") resp.ContentLength = -1 - gzReader, zerr := gzip.NewReader(resp.Body) - if zerr != nil { - pc.close() - err = zerr - } else { - resp.Body = &readerAndCloser{gzReader, resp.Body} - } + resp.Body = &gzipReader{body: resp.Body} } resp.Body = &bodyEOFSignal{body: resp.Body} } @@ -787,24 +846,18 @@ func (pc *persistConn) readLoop() { return nil } resp.Body.(*bodyEOFSignal).fn = func(err error) { - alive1 := alive - if err != nil { - alive1 = false - } - if alive1 && !pc.t.putIdleConn(pc) { - alive1 = false - } - if !alive1 || pc.isBroken() { - pc.close() - } - waitForBodyRead <- alive1 + waitForBodyRead <- alive && + err == nil && + !pc.sawEOF && + pc.wroteRequest() && + pc.t.putIdleConn(pc) } } if alive && !hasBody { - if !pc.t.putIdleConn(pc) { - alive = false - } + alive = !pc.sawEOF && + pc.wroteRequest() && + pc.t.putIdleConn(pc) } rc.ch <- responseAndError{resp, err} @@ -812,10 +865,14 @@ func (pc *persistConn) readLoop() { // Wait for the just-returned response body to be fully consumed // before we race and peek on the underlying bufio reader. if waitForBodyRead != nil { - alive = <-waitForBodyRead + select { + case alive = <-waitForBodyRead: + case <-pc.closech: + alive = false + } } - pc.t.setReqConn(rc.req, nil) + pc.t.setReqCanceler(rc.req, nil) if !alive { pc.close() @@ -837,14 +894,44 @@ func (pc *persistConn) writeLoop() { } if err != nil { pc.markBroken() + wr.req.Request.closeBody() } - wr.ch <- err + pc.writeErrCh <- err // to the body reader, which might recycle us + wr.ch <- err // to the roundTrip function case <-pc.closech: return } } } +// wroteRequest is a check before recycling a connection that the previous write +// (from writeLoop above) happened and was successful. +func (pc *persistConn) wroteRequest() bool { + select { + case err := <-pc.writeErrCh: + // Common case: the write happened well before the response, so + // avoid creating a timer. + return err == nil + default: + // Rare case: the request was written in writeLoop above but + // before it could send to pc.writeErrCh, the reader read it + // all, processed it, and called us here. In this case, give the + // write goroutine a bit of time to finish its send. + // + // Less rare case: We also get here in the legitimate case of + // Issue 7569, where the writer is still writing (or stalled), + // but the server has already replied. In this case, we don't + // want to wait too long, and we want to return false so this + // connection isn't re-used. + select { + case err := <-pc.writeErrCh: + return err == nil + case <-time.After(50 * time.Millisecond): + return false + } + } +} + type responseAndError struct { res *Response err error @@ -882,7 +969,7 @@ var errTimeout error = &httpError{err: "net/http: timeout awaiting response head var errClosed error = &httpError{err: "net/http: transport closed before response was received"} func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) { - pc.t.setReqConn(req.Request, pc) + pc.t.setReqCanceler(req.Request, pc.cancelRequest) pc.lk.Lock() pc.numExpectedResponses++ headerFn := pc.mutateHeaderFunc @@ -967,7 +1054,7 @@ WaitResponse: pc.lk.Unlock() if re.err != nil { - pc.t.setReqConn(req.Request, nil) + pc.t.setReqCanceler(req.Request, nil) } return re.res, re.err } @@ -992,6 +1079,7 @@ func (pc *persistConn) closeLocked() { if !pc.closed { pc.conn.Close() pc.closed = true + close(pc.closech) } pc.mutateHeaderFunc = nil } @@ -1074,7 +1162,47 @@ func (es *bodyEOFSignal) condfn(err error) { es.fn = nil } +// gzipReader wraps a response body so it can lazily +// call gzip.NewReader on the first call to Read +type gzipReader struct { + body io.ReadCloser // underlying Response.Body + zr io.Reader // lazily-initialized gzip reader +} + +func (gz *gzipReader) Read(p []byte) (n int, err error) { + if gz.zr == nil { + gz.zr, err = gzip.NewReader(gz.body) + if err != nil { + return 0, err + } + } + return gz.zr.Read(p) +} + +func (gz *gzipReader) Close() error { + return gz.body.Close() +} + type readerAndCloser struct { io.Reader io.Closer } + +type tlsHandshakeTimeoutError struct{} + +func (tlsHandshakeTimeoutError) Timeout() bool { return true } +func (tlsHandshakeTimeoutError) Temporary() bool { return true } +func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" } + +type noteEOFReader struct { + r io.Reader + sawEOF *bool +} + +func (nr noteEOFReader) Read(p []byte) (n int, err error) { + n, err = nr.r.Read(p) + if err == io.EOF { + *nr.sawEOF = true + } + return +} diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go index 2678d71b1de..964ca0fca54 100644 --- a/libgo/go/net/http/transport_test.go +++ b/libgo/go/net/http/transport_test.go @@ -11,9 +11,12 @@ import ( "bytes" "compress/gzip" "crypto/rand" + "crypto/tls" + "errors" "fmt" "io" "io/ioutil" + "log" "net" "net/http" . "net/http" @@ -54,21 +57,21 @@ func (c *testCloseConn) Close() error { // been closed. type testConnSet struct { t *testing.T + mu sync.Mutex // guards closed and list closed map[net.Conn]bool list []net.Conn // in order created - mutex sync.Mutex } func (tcs *testConnSet) insert(c net.Conn) { - tcs.mutex.Lock() - defer tcs.mutex.Unlock() + tcs.mu.Lock() + defer tcs.mu.Unlock() tcs.closed[c] = false tcs.list = append(tcs.list, c) } func (tcs *testConnSet) remove(c net.Conn) { - tcs.mutex.Lock() - defer tcs.mutex.Unlock() + tcs.mu.Lock() + defer tcs.mu.Unlock() tcs.closed[c] = true } @@ -91,11 +94,19 @@ func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, e } func (tcs *testConnSet) check(t *testing.T) { - tcs.mutex.Lock() - defer tcs.mutex.Unlock() - - for i, c := range tcs.list { - if !tcs.closed[c] { + tcs.mu.Lock() + defer tcs.mu.Unlock() + for i := 4; i >= 0; i-- { + for i, c := range tcs.list { + if tcs.closed[c] { + continue + } + if i != 0 { + tcs.mu.Unlock() + time.Sleep(50 * time.Millisecond) + tcs.mu.Lock() + continue + } t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list)) } } @@ -347,10 +358,11 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) { resp, err := c.Get(ts.URL) if err != nil { t.Error(err) + return } - _, err = ioutil.ReadAll(resp.Body) - if err != nil { - t.Fatalf("ReadAll: %v", err) + if _, err := ioutil.ReadAll(resp.Body); err != nil { + t.Errorf("ReadAll: %v", err) + return } donech <- true } @@ -791,6 +803,33 @@ func TestTransportGzipRecursive(t *testing.T) { } } +// golang.org/issue/7750: request fails when server replies with +// a short gzip body +func TestTransportGzipShort(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Content-Encoding", "gzip") + w.Write([]byte{0x1f, 0x8b}) + })) + defer ts.Close() + + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + res, err := c.Get(ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + _, err = ioutil.ReadAll(res.Body) + if err == nil { + t.Fatal("Expect an error from reading a body.") + } + if err != io.ErrUnexpectedEOF { + t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err) + } +} + // tests that persistent goroutine connections shut down when no longer desired. func TestTransportPersistConnLeak(t *testing.T) { if runtime.GOOS == "plan9" { @@ -1211,9 +1250,13 @@ func TestTransportResponseHeaderTimeout(t *testing.T) { if testing.Short() { t.Skip("skipping timeout test in -short mode") } + inHandler := make(chan bool, 1) mux := NewServeMux() - mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {}) + mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) { + inHandler <- true + }) mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) { + inHandler <- true time.Sleep(2 * time.Second) }) ts := httptest.NewServer(mux) @@ -1236,6 +1279,12 @@ func TestTransportResponseHeaderTimeout(t *testing.T) { } for i, tt := range tests { res, err := c.Get(ts.URL + tt.path) + select { + case <-inHandler: + case <-time.After(5 * time.Second): + t.Errorf("never entered handler for test index %d, %s", i, tt.path) + continue + } if err != nil { uerr, ok := err.(*url.Error) if !ok { @@ -1321,6 +1370,60 @@ func TestTransportCancelRequest(t *testing.T) { } } +func TestTransportCancelRequestInDial(t *testing.T) { + defer afterTest(t) + if testing.Short() { + t.Skip("skipping test in -short mode") + } + var logbuf bytes.Buffer + eventLog := log.New(&logbuf, "", 0) + + unblockDial := make(chan bool) + defer close(unblockDial) + + inDial := make(chan bool) + tr := &Transport{ + Dial: func(network, addr string) (net.Conn, error) { + eventLog.Println("dial: blocking") + inDial <- true + <-unblockDial + return nil, errors.New("nope") + }, + } + cl := &Client{Transport: tr} + gotres := make(chan bool) + req, _ := NewRequest("GET", "http://something.no-network.tld/", nil) + go func() { + _, err := cl.Do(req) + eventLog.Printf("Get = %v", err) + gotres <- true + }() + + select { + case <-inDial: + case <-time.After(5 * time.Second): + t.Fatal("timeout; never saw blocking dial") + } + + eventLog.Printf("canceling") + tr.CancelRequest(req) + + select { + case <-gotres: + case <-time.After(5 * time.Second): + panic("hang. events are: " + logbuf.String()) + } + + got := logbuf.String() + want := `dial: blocking +canceling +Get = Get http://something.no-network.tld/: net/http: request canceled while waiting for connection +` + if got != want { + t.Errorf("Got events:\n%s\nWant:\n%s", got, want) + } +} + // golang.org/issue/3672 -- Client can't close HTTP stream // Calling Close on a Response.Body used to just read until EOF. // Now it actually closes the TCP connection. @@ -1450,8 +1553,10 @@ func TestTransportSocketLateBinding(t *testing.T) { dialGate := make(chan bool, 1) tr := &Transport{ Dial: func(n, addr string) (net.Conn, error) { - <-dialGate - return net.Dial(n, addr) + if <-dialGate { + return net.Dial(n, addr) + } + return nil, errors.New("manually closed") }, DisableKeepAlives: false, } @@ -1486,7 +1591,7 @@ func TestTransportSocketLateBinding(t *testing.T) { t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr) } barRes.Body.Close() - dialGate <- true + dialGate <- false } // Issue 2184 @@ -1637,10 +1742,7 @@ var proxyFromEnvTests = []proxyFromEnvTest{ } func TestProxyFromEnvironment(t *testing.T) { - os.Setenv("HTTP_PROXY", "") - os.Setenv("http_proxy", "") - os.Setenv("NO_PROXY", "") - os.Setenv("no_proxy", "") + ResetProxyEnv() for _, tt := range proxyFromEnvTests { os.Setenv("HTTP_PROXY", tt.env) os.Setenv("NO_PROXY", tt.noenv) @@ -1722,6 +1824,308 @@ func TestTransportClosesRequestBody(t *testing.T) { } } +func TestTransportTLSHandshakeTimeout(t *testing.T) { + defer afterTest(t) + if testing.Short() { + t.Skip("skipping in short mode") + } + ln := newLocalListener(t) + defer ln.Close() + testdonec := make(chan struct{}) + defer close(testdonec) + + go func() { + c, err := ln.Accept() + if err != nil { + t.Error(err) + return + } + <-testdonec + c.Close() + }() + + getdonec := make(chan struct{}) + go func() { + defer close(getdonec) + tr := &Transport{ + Dial: func(_, _ string) (net.Conn, error) { + return net.Dial("tcp", ln.Addr().String()) + }, + TLSHandshakeTimeout: 250 * time.Millisecond, + } + cl := &Client{Transport: tr} + _, err := cl.Get("https://dummy.tld/") + if err == nil { + t.Error("expected error") + return + } + ue, ok := err.(*url.Error) + if !ok { + t.Errorf("expected url.Error; got %#v", err) + return + } + ne, ok := ue.Err.(net.Error) + if !ok { + t.Errorf("expected net.Error; got %#v", err) + return + } + if !ne.Timeout() { + t.Errorf("expected timeout error; got %v", err) + } + if !strings.Contains(err.Error(), "handshake timeout") { + t.Errorf("expected 'handshake timeout' in error; got %v", err) + } + }() + select { + case <-getdonec: + case <-time.After(5 * time.Second): + t.Error("test timeout; TLS handshake hung?") + } +} + +// Trying to repro golang.org/issue/3514 +func TestTLSServerClosesConnection(t *testing.T) { + defer afterTest(t) + if runtime.GOOS == "windows" { + t.Skip("skipping flaky test on Windows; golang.org/issue/7634") + } + closedc := make(chan bool, 1) + ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { + if strings.Contains(r.URL.Path, "/keep-alive-then-die") { + conn, _, _ := w.(Hijacker).Hijack() + conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) + conn.Close() + closedc <- true + return + } + fmt.Fprintf(w, "hello") + })) + defer ts.Close() + tr := &Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + defer tr.CloseIdleConnections() + client := &Client{Transport: tr} + + var nSuccess = 0 + var errs []error + const trials = 20 + for i := 0; i < trials; i++ { + tr.CloseIdleConnections() + res, err := client.Get(ts.URL + "/keep-alive-then-die") + if err != nil { + t.Fatal(err) + } + <-closedc + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if string(slurp) != "foo" { + t.Errorf("Got %q, want foo", slurp) + } + + // Now try again and see if we successfully + // pick a new connection. + res, err = client.Get(ts.URL + "/") + if err != nil { + errs = append(errs, err) + continue + } + slurp, err = ioutil.ReadAll(res.Body) + if err != nil { + errs = append(errs, err) + continue + } + nSuccess++ + } + if nSuccess > 0 { + t.Logf("successes = %d of %d", nSuccess, trials) + } else { + t.Errorf("All runs failed:") + } + for _, err := range errs { + t.Logf(" err: %v", err) + } +} + +// byteFromChanReader is an io.Reader that reads a single byte at a +// time from the channel. When the channel is closed, the reader +// returns io.EOF. +type byteFromChanReader chan byte + +func (c byteFromChanReader) Read(p []byte) (n int, err error) { + if len(p) == 0 { + return + } + b, ok := <-c + if !ok { + return 0, io.EOF + } + p[0] = b + return 1, nil +} + +// Verifies that the Transport doesn't reuse a connection in the case +// where the server replies before the request has been fully +// written. We still honor that reply (see TestIssue3595), but don't +// send future requests on the connection because it's then in a +// questionable state. +// golang.org/issue/7569 +func TestTransportNoReuseAfterEarlyResponse(t *testing.T) { + defer afterTest(t) + var sconn struct { + sync.Mutex + c net.Conn + } + var getOkay bool + closeConn := func() { + sconn.Lock() + defer sconn.Unlock() + if sconn.c != nil { + sconn.c.Close() + sconn.c = nil + if !getOkay { + t.Logf("Closed server connection") + } + } + } + defer closeConn() + + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + if r.Method == "GET" { + io.WriteString(w, "bar") + return + } + conn, _, _ := w.(Hijacker).Hijack() + sconn.Lock() + sconn.c = conn + sconn.Unlock() + conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive + go io.Copy(ioutil.Discard, conn) + })) + defer ts.Close() + tr := &Transport{} + defer tr.CloseIdleConnections() + client := &Client{Transport: tr} + + const bodySize = 256 << 10 + finalBit := make(byteFromChanReader, 1) + req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit)) + req.ContentLength = bodySize + res, err := client.Do(req) + if err := wantBody(res, err, "foo"); err != nil { + t.Errorf("POST response: %v", err) + } + donec := make(chan bool) + go func() { + defer close(donec) + res, err = client.Get(ts.URL) + if err := wantBody(res, err, "bar"); err != nil { + t.Errorf("GET response: %v", err) + return + } + getOkay = true // suppress test noise + }() + time.AfterFunc(5*time.Second, closeConn) + select { + case <-donec: + finalBit <- 'x' // unblock the writeloop of the first Post + close(finalBit) + case <-time.After(7 * time.Second): + t.Fatal("timeout waiting for GET request to finish") + } +} + +type errorReader struct { + err error +} + +func (e errorReader) Read(p []byte) (int, error) { return 0, e.err } + +type closerFunc func() error + +func (f closerFunc) Close() error { return f() } + +// Issue 6981 +func TestTransportClosesBodyOnError(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping test; see http://golang.org/issue/7782") + } + defer afterTest(t) + readBody := make(chan error, 1) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + _, err := ioutil.ReadAll(r.Body) + readBody <- err + })) + defer ts.Close() + fakeErr := errors.New("fake error") + didClose := make(chan bool, 1) + req, _ := NewRequest("POST", ts.URL, struct { + io.Reader + io.Closer + }{ + io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}), + closerFunc(func() error { + select { + case didClose <- true: + default: + } + return nil + }), + }) + res, err := DefaultClient.Do(req) + if res != nil { + defer res.Body.Close() + } + if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) { + t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error()) + } + select { + case err := <-readBody: + if err == nil { + t.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'") + } + case <-time.After(5 * time.Second): + t.Error("timeout waiting for server handler to complete") + } + select { + case <-didClose: + default: + t.Errorf("didn't see Body.Close") + } +} + +func wantBody(res *http.Response, err error, want string) error { + if err != nil { + return err + } + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("error reading body: %v", err) + } + if string(slurp) != want { + return fmt.Errorf("body = %q; want %q", slurp, want) + } + if err := res.Body.Close(); err != nil { + return fmt.Errorf("body Close = %v", err) + } + return nil +} + +func newLocalListener(t *testing.T) net.Listener { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + ln, err = net.Listen("tcp6", "[::1]:0") + } + if err != nil { + t.Fatal(err) + } + return ln +} + type countCloseReader struct { n *int io.Reader diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go index 0713e9cd6a9..2e9f1ebc679 100644 --- a/libgo/go/net/interface.go +++ b/libgo/go/net/interface.go @@ -7,11 +7,11 @@ package net import "errors" var ( - errInvalidInterface = errors.New("net: invalid interface") - errInvalidInterfaceIndex = errors.New("net: invalid interface index") - errInvalidInterfaceName = errors.New("net: invalid interface name") - errNoSuchInterface = errors.New("net: no such interface") - errNoSuchMulticastInterface = errors.New("net: no such multicast interface") + errInvalidInterface = errors.New("invalid network interface") + errInvalidInterfaceIndex = errors.New("invalid network interface index") + errInvalidInterfaceName = errors.New("invalid network interface name") + errNoSuchInterface = errors.New("no such network interface") + errNoSuchMulticastInterface = errors.New("no such multicast network interface") ) // Interface represents a mapping between network interface name diff --git a/libgo/go/net/interface_stub.go b/libgo/go/net/interface_stub.go index a4eb731da44..c38fb7f7651 100644 --- a/libgo/go/net/interface_stub.go +++ b/libgo/go/net/interface_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build plan9 +// +build nacl plan9 solaris package net diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go index ea183f1d3eb..0632dafc65e 100644 --- a/libgo/go/net/ipraw_test.go +++ b/libgo/go/net/ipraw_test.go @@ -247,7 +247,7 @@ var ipConnLocalNameTests = []struct { func TestIPConnLocalName(t *testing.T) { switch runtime.GOOS { - case "plan9", "windows": + case "nacl", "plan9", "windows": t.Skipf("skipping test on %q", runtime.GOOS) default: if os.Getuid() != 0 { @@ -277,7 +277,7 @@ func TestIPConnRemoteName(t *testing.T) { } } - raddr := &IPAddr{IP: IPv4(127, 0, 0, 10).To4()} + raddr := &IPAddr{IP: IPv4(127, 0, 0, 1).To4()} c, err := DialIP("ip:tcp", &IPAddr{IP: IPv4(127, 0, 0, 1)}, raddr) if err != nil { t.Fatalf("DialIP failed: %v", err) diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go index a1a008ac413..bbb3f3ed66c 100644 --- a/libgo/go/net/iprawsock_posix.go +++ b/libgo/go/net/iprawsock_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package net @@ -79,7 +79,7 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) { // TODO(cw,rsc): consider using readv if we know the family // type to avoid the header trim/copy var addr *IPAddr - n, sa, err := c.fd.ReadFrom(b) + n, sa, err := c.fd.readFrom(b) switch sa := sa.(type) { case *syscall.SockaddrInet4: addr = &IPAddr{IP: sa.Addr[0:]} @@ -112,7 +112,7 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err return 0, 0, 0, nil, syscall.EINVAL } var sa syscall.Sockaddr - n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob) + n, oobn, flags, sa, err = c.fd.readMsg(b, oob) switch sa := sa.(type) { case *syscall.SockaddrInet4: addr = &IPAddr{IP: sa.Addr[0:]} @@ -133,6 +133,9 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) { if !c.ok() { return 0, syscall.EINVAL } + if c.fd.isConnected { + return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + } if addr == nil { return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} } @@ -140,7 +143,7 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) { if err != nil { return 0, &OpError{"write", c.fd.net, addr, err} } - return c.fd.WriteTo(b, sa) + return c.fd.writeTo(b, sa) } // WriteTo implements the PacketConn WriteTo method. @@ -162,6 +165,9 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error if !c.ok() { return 0, 0, syscall.EINVAL } + if c.fd.isConnected { + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + } if addr == nil { return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} } @@ -169,7 +175,7 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error if err != nil { return 0, 0, &OpError{"write", c.fd.net, addr, err} } - return c.fd.WriteMsg(b, oob, sa) + return c.fd.writeMsg(b, oob, sa) } // DialIP connects to the remote address raddr on the network protocol diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go index 8b586ef7c3e..dda85780308 100644 --- a/libgo/go/net/ipsock.go +++ b/libgo/go/net/ipsock.go @@ -16,7 +16,7 @@ var ( // networking functionality. supportsIPv4 bool - // supportsIPv6 reports whether the platfrom supports IPv6 + // supportsIPv6 reports whether the platform supports IPv6 // networking functionality. supportsIPv6 bool @@ -207,7 +207,7 @@ missingBrackets: } func splitHostZone(s string) (host, zone string) { - // The IPv6 scoped addressing zone identifer starts after the + // The IPv6 scoped addressing zone identifier starts after the // last percent sign. if i := last(s, '%'); i > 0 { host, zone = s[:i], s[i+1:] @@ -232,7 +232,7 @@ func JoinHostPort(host, port string) string { // address or a DNS name and returns an internet protocol family // address. It returns a list that contains a pair of different // address family addresses when addr is a DNS name and the name has -// mutiple address family records. The result contains at least one +// multiple address family records. The result contains at least one // address when error is nil. func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) { var ( diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go index 914ed50826f..94ceea31b03 100644 --- a/libgo/go/net/ipsock_plan9.go +++ b/libgo/go/net/ipsock_plan9.go @@ -60,12 +60,12 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) { if i >= 0 { addr = ParseIP(s[:i]) if addr == nil { - return nil, 0, errors.New("net: parsing IP failed") + return nil, 0, errors.New("parsing IP failed") } } p, _, ok := dtoi(s[i+1:], 0) if !ok { - return nil, 0, errors.New("net: parsing port failed") + return nil, 0, errors.New("parsing port failed") } if p < 0 || p > 0xFFFF { return nil, 0, &AddrError{"invalid port", string(p)} diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go index a83e5256174..2ba4c8efd53 100644 --- a/libgo/go/net/ipsock_posix.go +++ b/libgo/go/net/ipsock_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows // Internet protocol family sockets for POSIX @@ -40,12 +40,13 @@ func probeIPv4Stack() bool { func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { var probes = []struct { laddr TCPAddr + value int ok bool }{ // IPv6 communication capability - {TCPAddr{IP: ParseIP("::1")}, false}, + {laddr: TCPAddr{IP: ParseIP("::1")}, value: 1}, // IPv6 IPv4-mapped address communication capability - {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false}, + {laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0}, } for i := range probes { @@ -54,7 +55,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { continue } defer closesocket(s) - syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value) sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6) if err != nil { continue diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go index 2ccd997c2cb..b80ac10e0d9 100644 --- a/libgo/go/net/lookup_plan9.go +++ b/libgo/go/net/lookup_plan9.go @@ -63,7 +63,7 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) { } f := getFields(lines[0]) if len(f) < 2 { - return "", "", errors.New("net: bad response from ndb/cs") + return "", "", errors.New("bad response from ndb/cs") } clone, dest = f[0], f[1] return @@ -199,7 +199,7 @@ func lookupCNAME(name string) (cname string, err error) { return f[2] + ".", nil } } - return "", errors.New("net: bad response from ndb/dns") + return "", errors.New("bad response from ndb/dns") } func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go index 59e9f63210c..b1d2f8f31a9 100644 --- a/libgo/go/net/lookup_unix.go +++ b/libgo/go/net/lookup_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package net diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go index 4b332c1b5be..ba0778caa73 100644 --- a/libgo/go/net/mail/message.go +++ b/libgo/go/net/mail/message.go @@ -363,7 +363,7 @@ func (p *addrParser) consumePhrase() (phrase string, err error) { // Ignore any error if we got at least one word. if err != nil && len(words) == 0 { debug.Printf("consumePhrase: hit err: %v", err) - return "", errors.New("mail: missing word in phrase") + return "", fmt.Errorf("mail: missing word in phrase: %v", err) } phrase = strings.Join(words, " ") return phrase, nil @@ -442,11 +442,11 @@ func (p *addrParser) len() int { func decodeRFC2047Word(s string) (string, error) { fields := strings.Split(s, "?") if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" { - return "", errors.New("mail: address not RFC 2047 encoded") + return "", errors.New("address not RFC 2047 encoded") } charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2]) if charset != "iso-8859-1" && charset != "utf-8" { - return "", fmt.Errorf("mail: charset not supported: %q", charset) + return "", fmt.Errorf("charset not supported: %q", charset) } in := bytes.NewBufferString(fields[3]) @@ -457,7 +457,7 @@ func decodeRFC2047Word(s string) (string, error) { case "q": r = qDecoder{r: in} default: - return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc) + return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc) } dec, err := ioutil.ReadAll(r) diff --git a/libgo/go/net/mail/message_test.go b/libgo/go/net/mail/message_test.go index 1bb4e8bc401..eb9c8cbdc9b 100644 --- a/libgo/go/net/mail/message_test.go +++ b/libgo/go/net/mail/message_test.go @@ -8,6 +8,7 @@ import ( "bytes" "io/ioutil" "reflect" + "strings" "testing" "time" ) @@ -116,6 +117,14 @@ func TestDateParsing(t *testing.T) { } } +func TestAddressParsingError(t *testing.T) { + const txt = "=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown@gmail.com>" + _, err := ParseAddress(txt) + if err == nil || !strings.Contains(err.Error(), "charset not supported") { + t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*charset not supported.*"`, txt, err) + } +} + func TestAddressParsing(t *testing.T) { tests := []struct { addrsStr string diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go index 5660fd42f8c..63dbce88e9a 100644 --- a/libgo/go/net/multicast_test.go +++ b/libgo/go/net/multicast_test.go @@ -25,8 +25,10 @@ var ipv4MulticastListenerTests = []struct { // port. func TestIPv4MulticastListener(t *testing.T) { switch runtime.GOOS { - case "plan9": + case "nacl", "plan9": t.Skipf("skipping test on %q", runtime.GOOS) + case "solaris": + t.Skipf("skipping test on solaris, see issue 7399") } closer := func(cs []*UDPConn) { @@ -93,8 +95,10 @@ var ipv6MulticastListenerTests = []struct { // port. func TestIPv6MulticastListener(t *testing.T) { switch runtime.GOOS { - case "plan9", "solaris": + case "plan9": t.Skipf("skipping test on %q", runtime.GOOS) + case "solaris": + t.Skipf("skipping test on solaris, see issue 7399") } if !supportsIPv6 { t.Skip("ipv6 is not supported") diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go index 2e6db555143..ca56af54fc6 100644 --- a/libgo/go/net/net.go +++ b/libgo/go/net/net.go @@ -275,7 +275,16 @@ type Listener interface { Addr() Addr } -var errMissingAddress = errors.New("missing address") +// Various errors contained in OpError. +var ( + // For connection setup and write operations. + errMissingAddress = errors.New("missing address") + + // For both read and write operations. + errTimeout error = &timeoutError{} + errClosing = errors.New("use of closed network connection") + ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection") +) // OpError is the error type usually returned by functions in the net // package. It describes the operation, network type, and address of @@ -337,10 +346,6 @@ func (e *timeoutError) Error() string { return "i/o timeout" } func (e *timeoutError) Timeout() bool { return true } func (e *timeoutError) Temporary() bool { return true } -var errTimeout error = &timeoutError{} - -var errClosing = errors.New("use of closed network connection") - type AddrError struct { Err string Addr string diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go index c9fb433ec91..bfed4d657fd 100644 --- a/libgo/go/net/net_test.go +++ b/libgo/go/net/net_test.go @@ -28,12 +28,14 @@ func TestShutdown(t *testing.T) { defer ln.Close() c, err := ln.Accept() if err != nil { - t.Fatalf("Accept: %v", err) + t.Errorf("Accept: %v", err) + return } var buf [10]byte n, err := c.Read(buf[:]) if n != 0 || err != io.EOF { - t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err) + t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err) + return } c.Write([]byte("response")) c.Close() @@ -62,7 +64,7 @@ func TestShutdown(t *testing.T) { func TestShutdownUnix(t *testing.T) { switch runtime.GOOS { - case "windows", "plan9": + case "nacl", "plan9", "windows": t.Skipf("skipping test on %q", runtime.GOOS) } f, err := ioutil.TempFile("", "go_net_unixtest") @@ -84,12 +86,14 @@ func TestShutdownUnix(t *testing.T) { go func() { c, err := ln.Accept() if err != nil { - t.Fatalf("Accept: %v", err) + t.Errorf("Accept: %v", err) + return } var buf [10]byte n, err := c.Read(buf[:]) if n != 0 || err != io.EOF { - t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err) + t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err) + return } c.Write([]byte("response")) c.Close() @@ -196,7 +200,8 @@ func TestTCPClose(t *testing.T) { go func() { c, err := Dial("tcp", l.Addr().String()) if err != nil { - t.Fatal(err) + t.Errorf("Dial: %v", err) + return } go read(c) diff --git a/libgo/go/net/packetconn_test.go b/libgo/go/net/packetconn_test.go index 945003f67ad..b6e4e76f930 100644 --- a/libgo/go/net/packetconn_test.go +++ b/libgo/go/net/packetconn_test.go @@ -15,12 +15,6 @@ import ( "time" ) -func strfunc(s string) func() string { - return func() string { - return s - } -} - func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) { switch net { case "udp": @@ -46,7 +40,7 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) { return b, nil case "unixgram": switch runtime.GOOS { - case "plan9", "windows": + case "nacl", "plan9", "windows": return nil, func() { t.Logf("skipping %q test on %q", net, runtime.GOOS) } @@ -62,12 +56,12 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) { var packetConnTests = []struct { net string - addr1 func() string - addr2 func() string + addr1 string + addr2 string }{ - {"udp", strfunc("127.0.0.1:0"), strfunc("127.0.0.1:0")}, - {"ip:icmp", strfunc("127.0.0.1"), strfunc("127.0.0.1")}, - {"unixgram", testUnixAddr, testUnixAddr}, + {"udp", "127.0.0.1:0", "127.0.0.1:0"}, + {"ip:icmp", "127.0.0.1", "127.0.0.1"}, + {"unixgram", testUnixAddr(), testUnixAddr()}, } func TestPacketConn(t *testing.T) { @@ -88,22 +82,21 @@ func TestPacketConn(t *testing.T) { continue } - addr1, addr2 := tt.addr1(), tt.addr2() - c1, err := ListenPacket(tt.net, addr1) + c1, err := ListenPacket(tt.net, tt.addr1) if err != nil { t.Fatalf("ListenPacket failed: %v", err) } - defer closer(c1, netstr[0], addr1, addr2) + defer closer(c1, netstr[0], tt.addr1, tt.addr2) c1.LocalAddr() c1.SetDeadline(time.Now().Add(100 * time.Millisecond)) c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) - c2, err := ListenPacket(tt.net, addr2) + c2, err := ListenPacket(tt.net, tt.addr2) if err != nil { t.Fatalf("ListenPacket failed: %v", err) } - defer closer(c2, netstr[0], addr1, addr2) + defer closer(c2, netstr[0], tt.addr1, tt.addr2) c2.LocalAddr() c2.SetDeadline(time.Now().Add(100 * time.Millisecond)) c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) @@ -145,12 +138,11 @@ func TestConnAndPacketConn(t *testing.T) { continue } - addr1, addr2 := tt.addr1(), tt.addr2() - c1, err := ListenPacket(tt.net, addr1) + c1, err := ListenPacket(tt.net, tt.addr1) if err != nil { t.Fatalf("ListenPacket failed: %v", err) } - defer closer(c1, netstr[0], addr1, addr2) + defer closer(c1, netstr[0], tt.addr1, tt.addr2) c1.LocalAddr() c1.SetDeadline(time.Now().Add(100 * time.Millisecond)) c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) diff --git a/libgo/go/net/port_unix.go b/libgo/go/net/port_unix.go index 3cd9ca2aa71..89558c1f029 100644 --- a/libgo/go/net/port_unix.go +++ b/libgo/go/net/port_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris // Read system port mappings from /etc/services @@ -10,12 +10,16 @@ package net import "sync" -var services map[string]map[string]int +// services contains minimal mappings between services names and port +// numbers for platforms that don't have a complete list of port numbers +// (some Solaris distros). +var services = map[string]map[string]int{ + "tcp": {"http": 80}, +} var servicesError error var onceReadServices sync.Once func readServices() { - services = make(map[string]map[string]int) var file *file if file, servicesError = open("/etc/services"); servicesError != nil { return @@ -29,7 +33,7 @@ func readServices() { if len(f) < 2 { continue } - portnet := f[1] // "tcp/80" + portnet := f[1] // "80/tcp" port, j, ok := dtoi(portnet, 0) if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' { continue diff --git a/libgo/go/net/protoconn_test.go b/libgo/go/net/protoconn_test.go index 5a8958b0866..12856b6c311 100644 --- a/libgo/go/net/protoconn_test.go +++ b/libgo/go/net/protoconn_test.go @@ -19,7 +19,7 @@ import ( // also uses /tmp directory in case it is prohibited to create UNIX // sockets in TMPDIR. func testUnixAddr() string { - f, err := ioutil.TempFile("/tmp", "nettest") + f, err := ioutil.TempFile("", "nettest") if err != nil { panic(err) } @@ -236,7 +236,7 @@ func TestIPConnSpecificMethods(t *testing.T) { func TestUnixListenerSpecificMethods(t *testing.T) { switch runtime.GOOS { - case "plan9", "windows": + case "nacl", "plan9", "windows": t.Skipf("skipping test on %q", runtime.GOOS) } @@ -278,7 +278,7 @@ func TestUnixListenerSpecificMethods(t *testing.T) { func TestUnixConnSpecificMethods(t *testing.T) { switch runtime.GOOS { - case "plan9", "windows": + case "nacl", "plan9", "windows": t.Skipf("skipping test on %q", runtime.GOOS) } diff --git a/libgo/go/net/rpc/client.go b/libgo/go/net/rpc/client.go index c524d0a0a2d..21f79b06844 100644 --- a/libgo/go/net/rpc/client.go +++ b/libgo/go/net/rpc/client.go @@ -39,14 +39,16 @@ type Call struct { // with a single Client, and a Client may be used by // multiple goroutines simultaneously. type Client struct { - mutex sync.Mutex // protects pending, seq, request - sending sync.Mutex + codec ClientCodec + + sending sync.Mutex + + mutex sync.Mutex // protects following request Request seq uint64 - codec ClientCodec pending map[uint64]*Call - closing bool - shutdown bool + closing bool // user has called Close + shutdown bool // server has told us to stop } // A ClientCodec implements writing of RPC requests and @@ -274,7 +276,7 @@ func Dial(network, address string) (*Client, error) { func (client *Client) Close() error { client.mutex.Lock() - if client.shutdown || client.closing { + if client.closing { client.mutex.Unlock() return ErrShutdown } diff --git a/libgo/go/net/rpc/client_test.go b/libgo/go/net/rpc/client_test.go new file mode 100644 index 00000000000..bbfc1ec3a3e --- /dev/null +++ b/libgo/go/net/rpc/client_test.go @@ -0,0 +1,36 @@ +// Copyright 2014 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. + +package rpc + +import ( + "errors" + "testing" +) + +type shutdownCodec struct { + responded chan int + closed bool +} + +func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil } +func (c *shutdownCodec) ReadResponseBody(interface{}) error { return nil } +func (c *shutdownCodec) ReadResponseHeader(*Response) error { + c.responded <- 1 + return errors.New("shutdownCodec ReadResponseHeader") +} +func (c *shutdownCodec) Close() error { + c.closed = true + return nil +} + +func TestCloseCodec(t *testing.T) { + codec := &shutdownCodec{responded: make(chan int)} + client := NewClientWithCodec(codec) + <-codec.responded + client.Close() + if !codec.closed { + t.Error("client.Close did not close codec") + } +} diff --git a/libgo/go/net/rpc/jsonrpc/all_test.go b/libgo/go/net/rpc/jsonrpc/all_test.go index 40d4b82d7f2..a433a365e88 100644 --- a/libgo/go/net/rpc/jsonrpc/all_test.go +++ b/libgo/go/net/rpc/jsonrpc/all_test.go @@ -5,6 +5,7 @@ package jsonrpc import ( + "bytes" "encoding/json" "errors" "fmt" @@ -12,6 +13,7 @@ import ( "io/ioutil" "net" "net/rpc" + "strings" "testing" ) @@ -202,6 +204,39 @@ func TestMalformedOutput(t *testing.T) { } } +func TestServerErrorHasNullResult(t *testing.T) { + var out bytes.Buffer + sc := NewServerCodec(struct { + io.Reader + io.Writer + io.Closer + }{ + Reader: strings.NewReader(`{"method": "Arith.Add", "id": "123", "params": []}`), + Writer: &out, + Closer: ioutil.NopCloser(nil), + }) + r := new(rpc.Request) + if err := sc.ReadRequestHeader(r); err != nil { + t.Fatal(err) + } + const valueText = "the value we don't want to see" + const errorText = "some error" + err := sc.WriteResponse(&rpc.Response{ + ServiceMethod: "Method", + Seq: 1, + Error: errorText, + }, valueText) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(out.String(), errorText) { + t.Fatalf("Response didn't contain expected error %q: %s", errorText, &out) + } + if strings.Contains(out.String(), valueText) { + t.Errorf("Response contains both an error and value: %s", &out) + } +} + func TestUnexpectedError(t *testing.T) { cli, srv := myPipe() go cli.PipeWriter.CloseWithError(errors.New("unexpected error!")) // reader will get this error diff --git a/libgo/go/net/rpc/jsonrpc/server.go b/libgo/go/net/rpc/jsonrpc/server.go index 16ec0fe9ad5..e6d37cfa64f 100644 --- a/libgo/go/net/rpc/jsonrpc/server.go +++ b/libgo/go/net/rpc/jsonrpc/server.go @@ -100,7 +100,6 @@ func (c *serverCodec) ReadRequestBody(x interface{}) error { var null = json.RawMessage([]byte("null")) func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error { - var resp serverResponse c.mutex.Lock() b, ok := c.pending[r.Seq] if !ok { @@ -114,10 +113,9 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error { // Invalid request so no id. Use JSON null. b = &null } - resp.Id = b - resp.Result = x + resp := serverResponse{Id: b} if r.Error == "" { - resp.Error = nil + resp.Result = x } else { resp.Error = r.Error } diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go index 3b9a88380cf..0dc4ddc2de0 100644 --- a/libgo/go/net/rpc/server_test.go +++ b/libgo/go/net/rpc/server_test.go @@ -594,7 +594,6 @@ func TestErrorAfterClientClose(t *testing.T) { } func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) { - b.StopTimer() once.Do(startServer) client, err := dial() if err != nil { @@ -604,33 +603,24 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) { // Synchronous calls args := &Args{7, 8} - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N) - var wg sync.WaitGroup - wg.Add(procs) - b.StartTimer() - - for p := 0; p < procs; p++ { - go func() { - reply := new(Reply) - for atomic.AddInt32(&N, -1) >= 0 { - err := client.Call("Arith.Add", args, reply) - if err != nil { - b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error()) - } - if reply.C != args.A+args.B { - b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B) - } + b.ResetTimer() + + b.RunParallel(func(pb *testing.PB) { + reply := new(Reply) + for pb.Next() { + err := client.Call("Arith.Add", args, reply) + if err != nil { + b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error()) } - wg.Done() - }() - } - wg.Wait() + if reply.C != args.A+args.B { + b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B) + } + } + }) } func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) { const MaxConcurrentCalls = 100 - b.StopTimer() once.Do(startServer) client, err := dial() if err != nil { @@ -647,7 +637,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) { wg.Add(procs) gate := make(chan bool, MaxConcurrentCalls) res := make(chan *Call, MaxConcurrentCalls) - b.StartTimer() + b.ResetTimer() for p := 0; p < procs; p++ { go func() { diff --git a/libgo/go/net/sendfile_dragonfly.go b/libgo/go/net/sendfile_dragonfly.go index a2219c16337..bc88fd3b907 100644 --- a/libgo/go/net/sendfile_dragonfly.go +++ b/libgo/go/net/sendfile_dragonfly.go @@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20 // if handled == false, sendFile performed no work. func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { // DragonFly uses 0 as the "until EOF" value. If you pass in more bytes than the - // file contains, it will loop back to the beginning ad nauseum until it's sent + // file contains, it will loop back to the beginning ad nauseam until it's sent // exactly the number of bytes told to. As such, we need to know exactly how many // bytes to send. var remain int64 = 0 diff --git a/libgo/go/net/sendfile_freebsd.go b/libgo/go/net/sendfile_freebsd.go index 42fe799efbd..ffc147262a8 100644 --- a/libgo/go/net/sendfile_freebsd.go +++ b/libgo/go/net/sendfile_freebsd.go @@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20 // if handled == false, sendFile performed no work. func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { // FreeBSD uses 0 as the "until EOF" value. If you pass in more bytes than the - // file contains, it will loop back to the beginning ad nauseum until it's sent + // file contains, it will loop back to the beginning ad nauseam until it's sent // exactly the number of bytes told to. As such, we need to know exactly how many // bytes to send. var remain int64 = 0 diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go index 3660849c182..03426ef0df1 100644 --- a/libgo/go/net/sendfile_stub.go +++ b/libgo/go/net/sendfile_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin netbsd openbsd +// +build darwin nacl netbsd openbsd solaris package net diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go index 9194a8ec24d..6a2bb924329 100644 --- a/libgo/go/net/server_test.go +++ b/libgo/go/net/server_test.go @@ -9,21 +9,20 @@ import ( "io" "os" "runtime" - "strconv" "testing" "time" ) -func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) bool { +func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxOnly bool) bool { switch runtime.GOOS { case "linux": - case "plan9", "windows": + case "nacl", "plan9", "windows": // "unix" sockets are not supported on Windows and Plan 9. if net == unixsotype { return true } default: - if net == unixsotype && linuxonly { + if net == unixsotype && linuxOnly { return true } } @@ -42,21 +41,15 @@ func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) return false } -func tempfile(filename string) string { - // use /tmp in case it is prohibited to create - // UNIX sockets in TMPDIR - return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid()) -} - var streamConnServerTests = []struct { - snet string // server side - saddr string - cnet string // client side - caddr string - ipv6 bool // test with underlying AF_INET6 socket - ipv4map bool // test with IPv6 IPv4-mapping functionality - empty bool // test with empty data - linux bool // test with abstract unix domain socket, a Linux-ism + snet string // server side + saddr string + cnet string // client side + caddr string + ipv6 bool // test with underlying AF_INET6 socket + ipv4map bool // test with IPv6 IPv4-mapping functionality + empty bool // test with empty data + linuxOnly bool // test with abstract unix domain socket, a Linux-ism }{ {snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"}, {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"}, @@ -93,13 +86,13 @@ var streamConnServerTests = []struct { {snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true}, - {snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")}, - {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true}, + {snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()}, + {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true}, } func TestStreamConnServer(t *testing.T) { for _, tt := range streamConnServerTests { - if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) { + if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) { continue } @@ -137,21 +130,28 @@ func TestStreamConnServer(t *testing.T) { } var seqpacketConnServerTests = []struct { - net string - saddr string // server address - caddr string // client address - empty bool // test with empty data + net string + saddr string // server address + caddr string // client address + empty bool // test with empty data + linuxOnly bool // test with abstract unix domain socket, a Linux-ism }{ - {net: "unixpacket", saddr: tempfile("/gotest3.net"), caddr: tempfile("gotest3.net.local")}, - {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"}, + {net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()}, + {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true}, } func TestSeqpacketConnServer(t *testing.T) { - if runtime.GOOS != "linux" { + switch runtime.GOOS { + case "darwin", "nacl", "openbsd", "plan9", "windows": + fallthrough + case "freebsd": // FreeBSD 8 doesn't support unixpacket t.Skipf("skipping test on %q", runtime.GOOS) } for _, tt := range seqpacketConnServerTests { + if runtime.GOOS != "linux" && tt.linuxOnly { + continue + } listening := make(chan string) done := make(chan int) switch tt.net { @@ -248,15 +248,15 @@ func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) { var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram") var datagramPacketConnServerTests = []struct { - snet string // server side - saddr string - cnet string // client side - caddr string - ipv6 bool // test with underlying AF_INET6 socket - ipv4map bool // test with IPv6 IPv4-mapping functionality - dial bool // test with Dial or DialUnix - empty bool // test with empty data - linux bool // test with abstract unix domain socket, a Linux-ism + snet string // server side + saddr string + cnet string // client side + caddr string + ipv6 bool // test with underlying AF_INET6 socket + ipv4map bool // test with IPv6 IPv4-mapping functionality + dial bool // test with Dial or DialUnix + empty bool // test with empty data + linuxOnly bool // test with abstract unix domain socket, a Linux-ism }{ {snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"}, {snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"}, @@ -301,12 +301,12 @@ var datagramPacketConnServerTests = []struct { {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true}, {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true}, - {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local")}, - {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true}, - {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), empty: true}, - {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true, empty: true}, + {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr()}, + {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true}, + {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), empty: true}, + {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true, empty: true}, - {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true}, + {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linuxOnly: true}, } func TestDatagramPacketConnServer(t *testing.T) { @@ -315,7 +315,7 @@ func TestDatagramPacketConnServer(t *testing.T) { } for _, tt := range datagramPacketConnServerTests { - if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) { + if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) { continue } diff --git a/libgo/go/net/smtp/smtp.go b/libgo/go/net/smtp/smtp.go index a0a478a8524..87dea442c46 100644 --- a/libgo/go/net/smtp/smtp.go +++ b/libgo/go/net/smtp/smtp.go @@ -264,6 +264,8 @@ func (c *Client) Data() (io.WriteCloser, error) { return &dataCloser{c, c.Text.DotWriter()}, nil } +var testHookStartTLS func(*tls.Config) // nil, except for tests + // SendMail connects to the server at addr, switches to TLS if // possible, authenticates with the optional mechanism a if possible, // and then sends an email from address from, to addresses to, with @@ -278,7 +280,11 @@ func SendMail(addr string, a Auth, from string, to []string, msg []byte) error { return err } if ok, _ := c.Extension("STARTTLS"); ok { - if err = c.StartTLS(nil); err != nil { + config := &tls.Config{ServerName: c.serverName} + if testHookStartTLS != nil { + testHookStartTLS(config) + } + if err = c.StartTLS(config); err != nil { return err } } diff --git a/libgo/go/net/smtp/smtp_test.go b/libgo/go/net/smtp/smtp_test.go index 2133dc7c7ba..3fba1ea5ae3 100644 --- a/libgo/go/net/smtp/smtp_test.go +++ b/libgo/go/net/smtp/smtp_test.go @@ -7,6 +7,8 @@ package smtp import ( "bufio" "bytes" + "crypto/tls" + "crypto/x509" "io" "net" "net/textproto" @@ -548,3 +550,145 @@ AUTH PLAIN AHVzZXIAcGFzcw== * QUIT ` + +func TestTLSClient(t *testing.T) { + ln := newLocalListener(t) + defer ln.Close() + errc := make(chan error) + go func() { + errc <- sendMail(ln.Addr().String()) + }() + conn, err := ln.Accept() + if err != nil { + t.Fatalf("failed to accept connection: %v", err) + } + defer conn.Close() + if err := serverHandle(conn, t); err != nil { + t.Fatalf("failed to handle connection: %v", err) + } + if err := <-errc; err != nil { + t.Fatalf("client error: %v", err) + } +} + +func newLocalListener(t *testing.T) net.Listener { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + ln, err = net.Listen("tcp6", "[::1]:0") + } + if err != nil { + t.Fatal(err) + } + return ln +} + +type smtpSender struct { + w io.Writer +} + +func (s smtpSender) send(f string) { + s.w.Write([]byte(f + "\r\n")) +} + +// smtp server, finely tailored to deal with our own client only! +func serverHandle(c net.Conn, t *testing.T) error { + send := smtpSender{c}.send + send("220 127.0.0.1 ESMTP service ready") + s := bufio.NewScanner(c) + for s.Scan() { + switch s.Text() { + case "EHLO localhost": + send("250-127.0.0.1 ESMTP offers a warm hug of welcome") + send("250-STARTTLS") + send("250 Ok") + case "STARTTLS": + send("220 Go ahead") + keypair, err := tls.X509KeyPair(localhostCert, localhostKey) + if err != nil { + return err + } + config := &tls.Config{Certificates: []tls.Certificate{keypair}} + c = tls.Server(c, config) + defer c.Close() + return serverHandleTLS(c, t) + default: + t.Fatalf("unrecognized command: %q", s.Text()) + } + } + return s.Err() +} + +func serverHandleTLS(c net.Conn, t *testing.T) error { + send := smtpSender{c}.send + s := bufio.NewScanner(c) + for s.Scan() { + switch s.Text() { + case "EHLO localhost": + send("250 Ok") + case "MAIL FROM:<joe1@example.com>": + send("250 Ok") + case "RCPT TO:<joe2@example.com>": + send("250 Ok") + case "DATA": + send("354 send the mail data, end with .") + send("250 Ok") + case "Subject: test": + case "": + case "howdy!": + case ".": + case "QUIT": + send("221 127.0.0.1 Service closing transmission channel") + return nil + default: + t.Fatalf("unrecognized command during TLS: %q", s.Text()) + } + } + return s.Err() +} + +func init() { + testRootCAs := x509.NewCertPool() + testRootCAs.AppendCertsFromPEM(localhostCert) + testHookStartTLS = func(config *tls.Config) { + config.RootCAs = testRootCAs + } +} + +func sendMail(hostPort string) error { + host, _, err := net.SplitHostPort(hostPort) + if err != nil { + return err + } + auth := PlainAuth("", "", "", host) + from := "joe1@example.com" + to := []string{"joe2@example.com"} + return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!")) +} + +// (copied from net/http/httptest) +// localhostCert is a PEM-encoded TLS cert with SAN IPs +// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end +// of ASN.1 time). +// generated from src/pkg/crypto/tls: +// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h +var localhostCert = []byte(`-----BEGIN CERTIFICATE----- +MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD +bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj +bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa +IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA +AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud +EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA +AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk +Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA== +-----END CERTIFICATE-----`) + +// localhostKey is the private key for localhostCert. +var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0 +0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV +NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d +AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW +MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD +EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA +1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE= +-----END RSA PRIVATE KEY-----`) diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go index 6c37109f5e4..48fb7852757 100644 --- a/libgo/go/net/sock_bsd.go +++ b/libgo/go/net/sock_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd netbsd openbsd +// +build darwin dragonfly freebsd nacl netbsd openbsd package net diff --git a/libgo/go/net/sock_cloexec.go b/libgo/go/net/sock_cloexec.go index 3f22cd8f570..dec81855b68 100644 --- a/libgo/go/net/sock_cloexec.go +++ b/libgo/go/net/sock_cloexec.go @@ -5,7 +5,7 @@ // This file implements sysSocket and accept for platforms that // provide a fast path for setting SetNonblock and CloseOnExec. -// +build linux +// +build freebsd linux package net @@ -13,18 +13,20 @@ import "syscall" // Wrapper around the socket system call that marks the returned file // descriptor as nonblocking and close-on-exec. -func sysSocket(f, t, p int) (int, error) { - s, err := syscall.Socket(f, t|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, p) - // The SOCK_NONBLOCK and SOCK_CLOEXEC flags were introduced in - // Linux 2.6.27. If we get an EINVAL error, fall back to - // using socket without them. - if err == nil || err != syscall.EINVAL { +func sysSocket(family, sotype, proto int) (int, error) { + s, err := syscall.Socket(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) + // On Linux the SOCK_NONBLOCK and SOCK_CLOEXEC flags were + // introduced in 2.6.27 kernel and on FreeBSD both flags were + // introduced in 10 kernel. If we get an EINVAL error on Linux + // or EPROTONOSUPPORT error on FreeBSD, fall back to using + // socket without them. + if err == nil || (err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL) { return s, err } // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() - s, err = syscall.Socket(f, t, p) + s, err = syscall.Socket(family, sotype, proto) if err == nil { syscall.CloseOnExec(s) } @@ -41,12 +43,19 @@ func sysSocket(f, t, p int) (int, error) { // Wrapper around the accept system call that marks the returned file // descriptor as nonblocking and close-on-exec. -func accept(fd int) (int, syscall.Sockaddr, error) { - nfd, sa, err := syscall.Accept4(fd, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) - // The accept4 system call was introduced in Linux 2.6.28. If - // we get an ENOSYS or EINVAL error, fall back to using accept. - if err == nil || (err != syscall.ENOSYS && err != syscall.EINVAL) { - return nfd, sa, err +func accept(s int) (int, syscall.Sockaddr, error) { + ns, sa, err := syscall.Accept4(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + // On Linux the accept4 system call was introduced in 2.6.28 + // kernel and on FreeBSD it was introduced in 10 kernel. If we + // get an ENOSYS error on both Linux and FreeBSD, or EINVAL + // error on Linux, fall back to using accept. + switch err { + default: // nil and errors other than the ones listed + return ns, sa, err + case syscall.ENOSYS: // syscall missing + case syscall.EINVAL: // some Linux use this instead of ENOSYS + case syscall.EACCES: // some Linux use this instead of ENOSYS + case syscall.EFAULT: // some Linux use this instead of ENOSYS } // See ../syscall/exec_unix.go for description of ForkLock. @@ -54,16 +63,16 @@ func accept(fd int) (int, syscall.Sockaddr, error) { // because we have put fd.sysfd into non-blocking mode. // However, a call to the File method will put it back into // blocking mode. We can't take that risk, so no use of ForkLock here. - nfd, sa, err = syscall.Accept(fd) + ns, sa, err = syscall.Accept(s) if err == nil { - syscall.CloseOnExec(nfd) + syscall.CloseOnExec(ns) } if err != nil { return -1, nil, err } - if err = syscall.SetNonblock(nfd, true); err != nil { - syscall.Close(nfd) + if err = syscall.SetNonblock(ns, true); err != nil { + syscall.Close(ns) return -1, nil, err } - return nfd, sa, nil + return ns, sa, nil } diff --git a/libgo/go/net/sock_posix.go b/libgo/go/net/sock_posix.go index c2d343c5858..a6ef874c9fd 100644 --- a/libgo/go/net/sock_posix.go +++ b/libgo/go/net/sock_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package net diff --git a/libgo/go/net/sock_solaris.go b/libgo/go/net/sock_solaris.go index 484e1fe461a..90fe9de894c 100644 --- a/libgo/go/net/sock_solaris.go +++ b/libgo/go/net/sock_solaris.go @@ -1,18 +1,13 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2009 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 solaris - -// Sockets for Solaris - package net -import ( - "syscall" -) +import "syscall" func maxListenerBacklog() int { - // The kernel does not track the limit. + // TODO: Implement this + // NOTE: Never return a number bigger than 1<<16 - 1. See issue 5030. return syscall.SOMAXCONN } diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go index 4b9c2f9afbe..2fa3b6f1d36 100644 --- a/libgo/go/net/sockopt_bsd.go +++ b/libgo/go/net/sockopt_bsd.go @@ -2,16 +2,29 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd netbsd openbsd +// +build darwin dragonfly freebsd nacl netbsd openbsd package net import ( "os" + "runtime" "syscall" ) func setDefaultSockopts(s, family, sotype int, ipv6only bool) error { + if runtime.GOOS == "dragonfly" && sotype != syscall.SOCK_RAW { + // On DragonFly BSD, we adjust the ephemeral port + // range because unlike other BSD systems its default + // port range doesn't conform to IANA recommendation + // as described in RFC 6355 and is pretty narrow. + switch family { + case syscall.AF_INET: + syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_PORTRANGE, syscall.IP_PORTRANGE_HIGH) + case syscall.AF_INET6: + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH) + } + } if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW { // Allow both IP versions even if the OS default // is otherwise. Note that some operating systems diff --git a/libgo/go/net/sockopt_posix.go b/libgo/go/net/sockopt_posix.go index ff3bc689940..921918c37f5 100644 --- a/libgo/go/net/sockopt_posix.go +++ b/libgo/go/net/sockopt_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package net diff --git a/libgo/go/net/sockopt_solaris.go b/libgo/go/net/sockopt_solaris.go new file mode 100644 index 00000000000..54c20b1409b --- /dev/null +++ b/libgo/go/net/sockopt_solaris.go @@ -0,0 +1,32 @@ +// Copyright 2011 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. + +package net + +import ( + "os" + "syscall" +) + +func setDefaultSockopts(s, family, sotype int, ipv6only bool) error { + if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW { + // Allow both IP versions even if the OS default + // is otherwise. Note that some operating systems + // never admit this option. + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only)) + } + // Allow broadcast. + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)) +} + +func setDefaultListenerSockopts(s int) error { + // Allow reuse of recently-used addresses. + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)) +} + +func setDefaultMulticastSockopts(s int) error { + // Allow multicast UDP and raw IP datagram sockets to listen + // concurrently across multiple listeners. + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)) +} diff --git a/libgo/go/net/sockoptip_bsd.go b/libgo/go/net/sockoptip_bsd.go index 2199e480d42..87132f0f461 100644 --- a/libgo/go/net/sockoptip_bsd.go +++ b/libgo/go/net/sockoptip_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd netbsd openbsd +// +build darwin dragonfly freebsd nacl netbsd openbsd package net diff --git a/libgo/go/net/sockoptip_posix.go b/libgo/go/net/sockoptip_posix.go index c2579be9114..b5c80e44909 100644 --- a/libgo/go/net/sockoptip_posix.go +++ b/libgo/go/net/sockoptip_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd windows package net diff --git a/libgo/go/net/sockoptip_stub.go b/libgo/go/net/sockoptip_stub.go new file mode 100644 index 00000000000..dcd3a22b57d --- /dev/null +++ b/libgo/go/net/sockoptip_stub.go @@ -0,0 +1,39 @@ +// Copyright 2011 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 solaris + +package net + +import "syscall" + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + // See golang.org/issue/7399. + return syscall.EINVAL +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + // See golang.org/issue/7399. + return syscall.EINVAL +} + +func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { + // See golang.org/issue/7399. + return syscall.EINVAL +} + +func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error { + // See golang.org/issue/7399. + return syscall.EINVAL +} + +func setIPv6MulticastLoopback(fd *netFD, v bool) error { + // See golang.org/issue/7399. + return syscall.EINVAL +} + +func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error { + // See golang.org/issue/7399. + return syscall.EINVAL +} diff --git a/libgo/go/net/sys_cloexec.go b/libgo/go/net/sys_cloexec.go index bbfcc1a4fc4..898fb7c0c2c 100644 --- a/libgo/go/net/sys_cloexec.go +++ b/libgo/go/net/sys_cloexec.go @@ -5,7 +5,7 @@ // This file implements sysSocket and accept for platforms that do not // provide a fast path for setting SetNonblock and CloseOnExec. -// +build darwin dragonfly freebsd netbsd openbsd +// +build darwin dragonfly nacl netbsd openbsd solaris package net @@ -13,10 +13,10 @@ import "syscall" // Wrapper around the socket system call that marks the returned file // descriptor as nonblocking and close-on-exec. -func sysSocket(f, t, p int) (int, error) { +func sysSocket(family, sotype, proto int) (int, error) { // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() - s, err := syscall.Socket(f, t, p) + s, err := syscall.Socket(family, sotype, proto) if err == nil { syscall.CloseOnExec(s) } @@ -33,22 +33,22 @@ func sysSocket(f, t, p int) (int, error) { // Wrapper around the accept system call that marks the returned file // descriptor as nonblocking and close-on-exec. -func accept(fd int) (int, syscall.Sockaddr, error) { +func accept(s int) (int, syscall.Sockaddr, error) { // See ../syscall/exec_unix.go for description of ForkLock. // It is probably okay to hold the lock across syscall.Accept // because we have put fd.sysfd into non-blocking mode. // However, a call to the File method will put it back into // blocking mode. We can't take that risk, so no use of ForkLock here. - nfd, sa, err := syscall.Accept(fd) + ns, sa, err := syscall.Accept(s) if err == nil { - syscall.CloseOnExec(nfd) + syscall.CloseOnExec(ns) } if err != nil { return -1, nil, err } - if err = syscall.SetNonblock(nfd, true); err != nil { - syscall.Close(nfd) + if err = syscall.SetNonblock(ns, true); err != nil { + syscall.Close(ns) return -1, nil, err } - return nfd, sa, nil + return ns, sa, nil } diff --git a/libgo/go/net/tcp_test.go b/libgo/go/net/tcp_test.go index 62fd99f5c0b..c04198ea000 100644 --- a/libgo/go/net/tcp_test.go +++ b/libgo/go/net/tcp_test.go @@ -97,6 +97,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { b.Fatalf("Listen failed: %v", err) } defer ln.Close() + serverSem := make(chan bool, numConcurrent) // Acceptor. go func() { for { @@ -104,9 +105,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { if err != nil { break } + serverSem <- true // Server connection. go func(c Conn) { - defer c.Close() + defer func() { + c.Close() + <-serverSem + }() if timeout { c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire. } @@ -119,13 +124,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { }(c) } }() - sem := make(chan bool, numConcurrent) + clientSem := make(chan bool, numConcurrent) for i := 0; i < conns; i++ { - sem <- true + clientSem <- true // Client connection. go func() { defer func() { - <-sem + <-clientSem }() c, err := Dial("tcp", ln.Addr().String()) if err != nil { @@ -144,8 +149,9 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { } }() } - for i := 0; i < cap(sem); i++ { - sem <- true + for i := 0; i < numConcurrent; i++ { + clientSem <- true + serverSem <- true } } @@ -185,7 +191,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { for p := 0; p < P; p++ { s, err := ln.Accept() if err != nil { - b.Fatalf("Accept failed: %v", err) + b.Errorf("Accept failed: %v", err) + return } servers[p] = s } @@ -217,7 +224,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { buf[0] = v _, err := c.Write(buf[:]) if err != nil { - b.Fatalf("Write failed: %v", err) + b.Errorf("Write failed: %v", err) + return } } }(clients[p]) @@ -232,7 +240,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { for i := 0; i < N; i++ { _, err := s.Read(buf[:]) if err != nil { - b.Fatalf("Read failed: %v", err) + b.Errorf("Read failed: %v", err) + return } pipe <- buf[0] } @@ -250,7 +259,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { buf[0] = v _, err := s.Write(buf[:]) if err != nil { - b.Fatalf("Write failed: %v", err) + b.Errorf("Write failed: %v", err) + return } } s.Close() @@ -263,7 +273,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { for i := 0; i < N; i++ { _, err := c.Read(buf[:]) if err != nil { - b.Fatalf("Read failed: %v", err) + b.Errorf("Read failed: %v", err) + return } } c.Close() @@ -388,7 +399,7 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) { {"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false}, } switch runtime.GOOS { - case "darwin", "freebsd", "opensbd", "netbsd": + case "darwin", "freebsd", "openbsd", "netbsd": tests = append(tests, []test{ {"tcp", "[localhost%" + ifi.Name + "]:0", true}, {"tcp6", "[localhost%" + ifi.Name + "]:0", true}, @@ -460,15 +471,25 @@ func TestTCPConcurrentAccept(t *testing.T) { wg.Done() }() } - for i := 0; i < 10*N; i++ { - c, err := Dial("tcp", ln.Addr().String()) + attempts := 10 * N + fails := 0 + d := &Dialer{Timeout: 200 * time.Millisecond} + for i := 0; i < attempts; i++ { + c, err := d.Dial("tcp", ln.Addr().String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + fails++ + } else { + c.Close() } - c.Close() } ln.Close() wg.Wait() + if fails > attempts/9 { // see issues 7400 and 7541 + t.Fatalf("too many Dial failed: %v", fails) + } + if fails > 0 { + t.Logf("# of failed Dials: %v", fails) + } } func TestTCPReadWriteMallocs(t *testing.T) { diff --git a/libgo/go/net/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go index 6e1a8b9a192..52019d7b4eb 100644 --- a/libgo/go/net/tcpsock_plan9.go +++ b/libgo/go/net/tcpsock_plan9.go @@ -32,7 +32,7 @@ func (c *TCPConn) CloseRead() error { if !c.ok() { return syscall.EINVAL } - return c.fd.CloseRead() + return c.fd.closeRead() } // CloseWrite shuts down the writing side of the TCP connection. @@ -41,20 +41,21 @@ func (c *TCPConn) CloseWrite() error { if !c.ok() { return syscall.EINVAL } - return c.fd.CloseWrite() + return c.fd.closeWrite() } -// SetLinger sets the behavior of Close() on a connection which still +// SetLinger sets the behavior of Close on a connection which still // has data waiting to be sent or to be acknowledged. // -// If sec < 0 (the default), Close returns immediately and the -// operating system finishes sending the data in the background. +// If sec < 0 (the default), the operating system finishes sending the +// data in the background. // -// If sec == 0, Close returns immediately and the operating system -// discards any unsent or unacknowledged data. +// If sec == 0, the operating system discards any unsent or +// unacknowledged data. // -// If sec > 0, Close blocks for at most sec seconds waiting for data -// to be sent and acknowledged. +// If sec > 0, the data is sent in the background as with sec < 0. On +// some operating systems after sec seconds have elapsed any remaining +// unsent data may be discarded. func (c *TCPConn) SetLinger(sec int) error { return syscall.EPLAN9 } diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go index 00c692e4233..b79b115ca5b 100644 --- a/libgo/go/net/tcpsock_posix.go +++ b/libgo/go/net/tcpsock_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package net @@ -78,7 +78,7 @@ func (c *TCPConn) CloseRead() error { if !c.ok() { return syscall.EINVAL } - return c.fd.CloseRead() + return c.fd.closeRead() } // CloseWrite shuts down the writing side of the TCP connection. @@ -87,20 +87,21 @@ func (c *TCPConn) CloseWrite() error { if !c.ok() { return syscall.EINVAL } - return c.fd.CloseWrite() + return c.fd.closeWrite() } -// SetLinger sets the behavior of Close() on a connection which still +// SetLinger sets the behavior of Close on a connection which still // has data waiting to be sent or to be acknowledged. // -// If sec < 0 (the default), Close returns immediately and the -// operating system finishes sending the data in the background. +// If sec < 0 (the default), the operating system finishes sending the +// data in the background. // -// If sec == 0, Close returns immediately and the operating system -// discards any unsent or unacknowledged data. +// If sec == 0, the operating system discards any unsent or +// unacknowledged data. // -// If sec > 0, Close blocks for at most sec seconds waiting for data -// to be sent and acknowledged. +// If sec > 0, the data is sent in the background as with sec < 0. On +// some operating systems after sec seconds have elapsed any remaining +// unsent data may be discarded. func (c *TCPConn) SetLinger(sec int) error { if !c.ok() { return syscall.EINVAL diff --git a/libgo/go/net/tcpsockopt_dragonfly.go b/libgo/go/net/tcpsockopt_dragonfly.go new file mode 100644 index 00000000000..d10a77773d8 --- /dev/null +++ b/libgo/go/net/tcpsockopt_dragonfly.go @@ -0,0 +1,29 @@ +// Copyright 2009 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. + +package net + +import ( + "os" + "syscall" + "time" +) + +// Set keep alive period. +func setKeepAlivePeriod(fd *netFD, d time.Duration) error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + + // The kernel expects milliseconds so round to next highest millisecond. + d += (time.Millisecond - time.Nanosecond) + msecs := int(time.Duration(d.Nanoseconds()) / time.Millisecond) + + err := os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs)) + if err != nil { + return err + } + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs)) +} diff --git a/libgo/go/net/tcpsockopt_posix.go b/libgo/go/net/tcpsockopt_posix.go index e03476ac634..6484bad4b45 100644 --- a/libgo/go/net/tcpsockopt_posix.go +++ b/libgo/go/net/tcpsockopt_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package net diff --git a/libgo/go/net/tcpsockopt_solaris.go b/libgo/go/net/tcpsockopt_solaris.go new file mode 100644 index 00000000000..eaab6b6787b --- /dev/null +++ b/libgo/go/net/tcpsockopt_solaris.go @@ -0,0 +1,27 @@ +// Copyright 2013 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. + +// TCP socket options for solaris + +package net + +import ( + "os" + "syscall" + "time" +) + +// Set keep alive period. +func setKeepAlivePeriod(fd *netFD, d time.Duration) error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + + // The kernel expects seconds so round to next highest second. + d += (time.Second - time.Nanosecond) + secs := int(d.Seconds()) + + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs)) +} diff --git a/libgo/go/net/tcpsockopt_unix.go b/libgo/go/net/tcpsockopt_unix.go index 89d9143b52e..2693a541d20 100644 --- a/libgo/go/net/tcpsockopt_unix.go +++ b/libgo/go/net/tcpsockopt_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build dragonfly freebsd linux netbsd +// +build freebsd linux nacl netbsd package net diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go index b0c07413c19..eea9207f252 100644 --- a/libgo/go/net/textproto/reader.go +++ b/libgo/go/net/textproto/reader.go @@ -562,19 +562,12 @@ const toLower = 'a' - 'A' // allowed to mutate the provided byte slice before returning the // string. func canonicalMIMEHeaderKey(a []byte) string { - // Look for it in commonHeaders , so that we can avoid an - // allocation by sharing the strings among all users - // of textproto. If we don't find it, a has been canonicalized - // so just return string(a). upper := true - lo := 0 - hi := len(commonHeaders) - for i := 0; i < len(a); i++ { + for i, c := range a { // Canonicalize: first letter upper case // and upper case after each dash. // (Host, User-Agent, If-Modified-Since). // MIME headers are ASCII only, so no Unicode issues. - c := a[i] if c == ' ' { c = '-' } else if upper && 'a' <= c && c <= 'z' { @@ -584,60 +577,61 @@ func canonicalMIMEHeaderKey(a []byte) string { } a[i] = c upper = c == '-' // for next time - - if lo < hi { - for lo < hi && (len(commonHeaders[lo]) <= i || commonHeaders[lo][i] < c) { - lo++ - } - for hi > lo && commonHeaders[hi-1][i] > c { - hi-- - } - } } - if lo < hi && len(commonHeaders[lo]) == len(a) { - return commonHeaders[lo] + // The compiler recognizes m[string(byteSlice)] as a special + // case, so a copy of a's bytes into a new string does not + // happen in this map lookup: + if v := commonHeader[string(a)]; v != "" { + return v } return string(a) } -var commonHeaders = []string{ - "Accept", - "Accept-Charset", - "Accept-Encoding", - "Accept-Language", - "Accept-Ranges", - "Cache-Control", - "Cc", - "Connection", - "Content-Id", - "Content-Language", - "Content-Length", - "Content-Transfer-Encoding", - "Content-Type", - "Cookie", - "Date", - "Dkim-Signature", - "Etag", - "Expires", - "From", - "Host", - "If-Modified-Since", - "If-None-Match", - "In-Reply-To", - "Last-Modified", - "Location", - "Message-Id", - "Mime-Version", - "Pragma", - "Received", - "Return-Path", - "Server", - "Set-Cookie", - "Subject", - "To", - "User-Agent", - "Via", - "X-Forwarded-For", - "X-Imforwards", - "X-Powered-By", +// commonHeader interns common header strings. +var commonHeader = make(map[string]string) + +func init() { + for _, v := range []string{ + "Accept", + "Accept-Charset", + "Accept-Encoding", + "Accept-Language", + "Accept-Ranges", + "Cache-Control", + "Cc", + "Connection", + "Content-Id", + "Content-Language", + "Content-Length", + "Content-Transfer-Encoding", + "Content-Type", + "Cookie", + "Date", + "Dkim-Signature", + "Etag", + "Expires", + "From", + "Host", + "If-Modified-Since", + "If-None-Match", + "In-Reply-To", + "Last-Modified", + "Location", + "Message-Id", + "Mime-Version", + "Pragma", + "Received", + "Return-Path", + "Server", + "Set-Cookie", + "Subject", + "To", + "User-Agent", + "Via", + "X-Forwarded-For", + "X-Imforwards", + "X-Powered-By", + } { + commonHeader[v] = v + } } diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go index cc12912b634..c89566635e1 100644 --- a/libgo/go/net/textproto/reader_test.go +++ b/libgo/go/net/textproto/reader_test.go @@ -247,24 +247,21 @@ func TestRFC959Lines(t *testing.T) { } func TestCommonHeaders(t *testing.T) { - // need to disable the commonHeaders-based optimization - // during this check, or we'd not be testing anything - oldch := commonHeaders - commonHeaders = []string{} - defer func() { commonHeaders = oldch }() - - last := "" - for _, h := range oldch { - if last > h { - t.Errorf("%v is out of order", h) - } - if last == h { - t.Errorf("%v is duplicated", h) + for h := range commonHeader { + if h != CanonicalMIMEHeaderKey(h) { + t.Errorf("Non-canonical header %q in commonHeader", h) } - if canon := CanonicalMIMEHeaderKey(h); h != canon { - t.Errorf("%v is not canonical", h) + } + t.Skip("gccgo escape analysis") + b := []byte("content-Length") + want := "Content-Length" + n := testing.AllocsPerRun(200, func() { + if x := canonicalMIMEHeaderKey(b); x != want { + t.Fatalf("canonicalMIMEHeaderKey(%q) = %q; want %q", b, x, want) } - last = h + }) + if n > 0 { + t.Errorf("canonicalMIMEHeaderKey allocs = %v; want 0", n) } } diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go index 35d427a69c0..9ef0c4d15cc 100644 --- a/libgo/go/net/timeout_test.go +++ b/libgo/go/net/timeout_test.go @@ -120,6 +120,9 @@ func TestReadTimeout(t *testing.T) { t.Fatalf("Read: expected err %v, got %v", errClosing, err) } default: + if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044 + break + } if err != errClosing { t.Fatalf("Read: expected err %v, got %v", errClosing, err) } @@ -348,7 +351,8 @@ func TestReadWriteDeadline(t *testing.T) { go func() { c, err := ln.Accept() if err != nil { - t.Fatalf("Accept: %v", err) + t.Errorf("Accept: %v", err) + return } defer c.Close() lnquit <- true @@ -493,10 +497,7 @@ func testVariousDeadlines(t *testing.T, maxProcs int) { clientc <- copyRes{n, err, d} }() - tooLong := 2 * time.Second - if runtime.GOOS == "windows" { - tooLong = 5 * time.Second - } + tooLong := 5 * time.Second select { case res := <-clientc: if isTimeout(res.err) { @@ -536,7 +537,8 @@ func TestReadDeadlineDataAvailable(t *testing.T) { go func() { c, err := ln.Accept() if err != nil { - t.Fatalf("Accept: %v", err) + t.Errorf("Accept: %v", err) + return } defer c.Close() n, err := c.Write([]byte(msg)) @@ -574,7 +576,8 @@ func TestWriteDeadlineBufferAvailable(t *testing.T) { go func() { c, err := ln.Accept() if err != nil { - t.Fatalf("Accept: %v", err) + t.Errorf("Accept: %v", err) + return } defer c.Close() c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past @@ -610,7 +613,8 @@ func TestAcceptDeadlineConnectionAvailable(t *testing.T) { go func() { c, err := Dial("tcp", ln.Addr().String()) if err != nil { - t.Fatalf("Dial: %v", err) + t.Errorf("Dial: %v", err) + return } defer c.Close() var buf [1]byte @@ -669,7 +673,8 @@ func TestProlongTimeout(t *testing.T) { s, err := ln.Accept() connected <- true if err != nil { - t.Fatalf("ln.Accept: %v", err) + t.Errorf("ln.Accept: %v", err) + return } defer s.Close() s.SetDeadline(time.Now().Add(time.Hour)) @@ -706,7 +711,7 @@ func TestProlongTimeout(t *testing.T) { func TestDeadlineRace(t *testing.T) { switch runtime.GOOS { - case "plan9": + case "nacl", "plan9": t.Skipf("skipping test on %q", runtime.GOOS) } diff --git a/libgo/go/net/udp_test.go b/libgo/go/net/udp_test.go index 6f4d2152c3c..e1778779cf5 100644 --- a/libgo/go/net/udp_test.go +++ b/libgo/go/net/udp_test.go @@ -201,6 +201,10 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) { {"udp", "[" + laddr + "%" + ifi.Name + "]:0", false}, {"udp6", "[" + laddr + "%" + ifi.Name + "]:0", false}, } + // The first udp test fails on DragonFly - see issue 7473. + if runtime.GOOS == "dragonfly" { + tests = tests[1:] + } switch runtime.GOOS { case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd": tests = append(tests, []test{ diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go index 0dd0dbd7114..4c99ae4af68 100644 --- a/libgo/go/net/udpsock.go +++ b/libgo/go/net/udpsock.go @@ -4,10 +4,6 @@ package net -import "errors" - -var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP") - // UDPAddr represents the address of a UDP end point. type UDPAddr struct { IP IP diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go index 142da8186f1..5dfba94e9a6 100644 --- a/libgo/go/net/udpsock_posix.go +++ b/libgo/go/net/udpsock_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package net @@ -64,7 +64,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { if !c.ok() { return 0, nil, syscall.EINVAL } - n, sa, err := c.fd.ReadFrom(b) + n, sa, err := c.fd.readFrom(b) switch sa := sa.(type) { case *syscall.SockaddrInet4: addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port} @@ -93,7 +93,7 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, return 0, 0, 0, nil, syscall.EINVAL } var sa syscall.Sockaddr - n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob) + n, oobn, flags, sa, err = c.fd.readMsg(b, oob) switch sa := sa.(type) { case *syscall.SockaddrInet4: addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port} @@ -124,7 +124,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { if err != nil { return 0, &OpError{"write", c.fd.net, addr, err} } - return c.fd.WriteTo(b, sa) + return c.fd.writeTo(b, sa) } // WriteTo implements the PacketConn WriteTo method. @@ -156,7 +156,7 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er if err != nil { return 0, 0, &OpError{"write", c.fd.net, addr, err} } - return c.fd.WriteMsg(b, oob, sa) + return c.fd.writeMsg(b, oob, sa) } // DialUDP connects to the remote address raddr on the network net, diff --git a/libgo/go/net/unix_test.go b/libgo/go/net/unix_test.go index 91df3ff8876..05643ddf9ae 100644 --- a/libgo/go/net/unix_test.go +++ b/libgo/go/net/unix_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !plan9,!windows +// +build !nacl,!plan9,!windows package net @@ -151,6 +151,73 @@ func TestUnixAutobindClose(t *testing.T) { ln.Close() } +func TestUnixgramWrite(t *testing.T) { + addr := testUnixAddr() + laddr, err := ResolveUnixAddr("unixgram", addr) + if err != nil { + t.Fatalf("ResolveUnixAddr failed: %v", err) + } + c, err := ListenPacket("unixgram", addr) + if err != nil { + t.Fatalf("ListenPacket failed: %v", err) + } + defer os.Remove(addr) + defer c.Close() + + testUnixgramWriteConn(t, laddr) + testUnixgramWritePacketConn(t, laddr) +} + +func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) { + c, err := Dial("unixgram", raddr.String()) + if err != nil { + t.Fatalf("Dial failed: %v", err) + } + defer c.Close() + + if _, err := c.(*UnixConn).WriteToUnix([]byte("Connection-oriented mode socket"), raddr); err == nil { + t.Fatal("WriteToUnix should fail") + } else if err.(*OpError).Err != ErrWriteToConnected { + t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err) + } + if _, err = c.(*UnixConn).WriteTo([]byte("Connection-oriented mode socket"), raddr); err == nil { + t.Fatal("WriteTo should fail") + } else if err.(*OpError).Err != ErrWriteToConnected { + t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err) + } + if _, _, err = c.(*UnixConn).WriteMsgUnix([]byte("Connection-oriented mode socket"), nil, raddr); err == nil { + t.Fatal("WriteTo should fail") + } else if err.(*OpError).Err != ErrWriteToConnected { + t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err) + } + if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil { + t.Fatalf("Write failed: %v", err) + } +} + +func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) { + addr := testUnixAddr() + c, err := ListenPacket("unixgram", addr) + if err != nil { + t.Fatalf("ListenPacket failed: %v", err) + } + defer os.Remove(addr) + defer c.Close() + + if _, err := c.(*UnixConn).WriteToUnix([]byte("Connectionless mode socket"), raddr); err != nil { + t.Fatalf("WriteToUnix failed: %v", err) + } + if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil { + t.Fatalf("WriteTo failed: %v", err) + } + if _, _, err := c.(*UnixConn).WriteMsgUnix([]byte("Connectionless mode socket"), nil, raddr); err != nil { + t.Fatalf("WriteMsgUnix failed: %v", err) + } + if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil { + t.Fatal("Write should fail") + } +} + func TestUnixConnLocalAndRemoteNames(t *testing.T) { for _, laddr := range []string{"", testUnixAddr()} { laddr := laddr diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go index 54d9d16c99e..2610779bfd2 100644 --- a/libgo/go/net/unixsock_posix.go +++ b/libgo/go/net/unixsock_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package net @@ -124,7 +124,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { if !c.ok() { return 0, nil, syscall.EINVAL } - n, sa, err := c.fd.ReadFrom(b) + n, sa, err := c.fd.readFrom(b) switch sa := sa.(type) { case *syscall.SockaddrUnix: if sa.Name != "" { @@ -151,7 +151,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd if !c.ok() { return 0, 0, 0, nil, syscall.EINVAL } - n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) + n, oobn, flags, sa, err := c.fd.readMsg(b, oob) switch sa := sa.(type) { case *syscall.SockaddrUnix: if sa.Name != "" { @@ -171,6 +171,9 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) { if !c.ok() { return 0, syscall.EINVAL } + if c.fd.isConnected { + return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + } if addr == nil { return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} } @@ -178,7 +181,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) { return 0, syscall.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} - return c.fd.WriteTo(b, sa) + return c.fd.writeTo(b, sa) } // WriteTo implements the PacketConn WriteTo method. @@ -200,14 +203,17 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err if !c.ok() { return 0, 0, syscall.EINVAL } + if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected { + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + } if addr != nil { if addr.Net != sotypeToNet(c.fd.sotype) { return 0, 0, syscall.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} - return c.fd.WriteMsg(b, oob, sa) + return c.fd.writeMsg(b, oob, sa) } - return c.fd.WriteMsg(b, oob, nil) + return c.fd.writeMsg(b, oob, nil) } // CloseRead shuts down the reading side of the Unix domain connection. @@ -216,7 +222,7 @@ func (c *UnixConn) CloseRead() error { if !c.ok() { return syscall.EINVAL } - return c.fd.CloseRead() + return c.fd.closeRead() } // CloseWrite shuts down the writing side of the Unix domain connection. @@ -225,7 +231,7 @@ func (c *UnixConn) CloseWrite() error { if !c.ok() { return syscall.EINVAL } - return c.fd.CloseWrite() + return c.fd.closeWrite() } // DialUnix connects to the remote address raddr on the network net, diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go index 3b3787202b7..75f650a2756 100644 --- a/libgo/go/net/url/url.go +++ b/libgo/go/net/url/url.go @@ -502,7 +502,7 @@ func (v Values) Set(key, value string) { v[key] = []string{value} } -// Add adds the key to value. It appends to any existing +// Add adds the value to key. It appends to any existing // values associated with key. func (v Values) Add(key, value string) { v[key] = append(v[key], value) diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go index 7578eb15b90..cad758f2385 100644 --- a/libgo/go/net/url/url_test.go +++ b/libgo/go/net/url/url_test.go @@ -251,6 +251,17 @@ var urltests = []URLTest{ }, "file:///home/adg/rabbits", }, + // "Windows" paths are no exception to the rule. + // See golang.org/issue/6027, especially comment #9. + { + "file:///C:/FooBar/Baz.txt", + &URL{ + Scheme: "file", + Host: "", + Path: "/C:/FooBar/Baz.txt", + }, + "file:///C:/FooBar/Baz.txt", + }, // case-insensitive scheme { "MaIlTo:webmaster@golang.org", diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go index 67c390283c7..d353e405e54 100644 --- a/libgo/go/os/dir_unix.go +++ b/libgo/go/os/dir_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package os diff --git a/libgo/go/os/doc.go b/libgo/go/os/doc.go index a954e313d13..389a8eb14cb 100644 --- a/libgo/go/os/doc.go +++ b/libgo/go/os/doc.go @@ -39,11 +39,14 @@ func (p *Process) Kill() error { // Wait waits for the Process to exit, and then returns a // ProcessState describing its status and an error, if any. // Wait releases any resources associated with the Process. +// On most operating systems, the Process must be a child +// of the current process or an error will be returned. func (p *Process) Wait() (*ProcessState, error) { return p.wait() } // Signal sends a signal to the Process. +// Sending Interrupt on Windows is not implemented. func (p *Process) Signal(sig Signal) error { return p.signal(sig) } diff --git a/libgo/go/os/error_unix.go b/libgo/go/os/error_unix.go index f281495e6b8..f2aabbb45c4 100644 --- a/libgo/go/os/error_unix.go +++ b/libgo/go/os/error_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package os diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go index 4680036fddc..a70ed0d20cb 100644 --- a/libgo/go/os/exec/exec.go +++ b/libgo/go/os/exec/exec.go @@ -13,7 +13,9 @@ import ( "io" "os" "path/filepath" + "runtime" "strconv" + "strings" "sync" "syscall" ) @@ -237,13 +239,51 @@ func (c *Cmd) Run() error { return c.Wait() } +// lookExtensions finds windows executable by its dir and path. +// It uses LookPath to try appropriate extensions. +// lookExtensions does not search PATH, instead it converts `prog` into `.\prog`. +func lookExtensions(path, dir string) (string, error) { + if filepath.Base(path) == path { + path = filepath.Join(".", path) + } + if dir == "" { + return LookPath(path) + } + if filepath.VolumeName(path) != "" { + return LookPath(path) + } + if len(path) > 1 && os.IsPathSeparator(path[0]) { + return LookPath(path) + } + dirandpath := filepath.Join(dir, path) + // We assume that LookPath will only add file extension. + lp, err := LookPath(dirandpath) + if err != nil { + return "", err + } + ext := strings.TrimPrefix(lp, dirandpath) + return path + ext, nil +} + // Start starts the specified command but does not wait for it to complete. +// +// The Wait method will return the exit code and release associated resources +// once the command exits. func (c *Cmd) Start() error { if c.lookPathErr != nil { c.closeDescriptors(c.closeAfterStart) c.closeDescriptors(c.closeAfterWait) return c.lookPathErr } + if runtime.GOOS == "windows" { + lp, err := lookExtensions(c.Path, c.Dir) + if err != nil { + c.closeDescriptors(c.closeAfterStart) + c.closeDescriptors(c.closeAfterWait) + return err + } + c.Path = lp + } if c.Process != nil { return errors.New("exec: already started") } @@ -304,6 +344,8 @@ func (e *ExitError) Error() string { // If the command fails to run or doesn't complete successfully, the // error is of type *ExitError. Other error types may be // returned for I/O problems. +// +// Wait releases any resources associated with the Cmd. func (c *Cmd) Wait() error { if c.Process == nil { return errors.New("exec: not started") @@ -387,15 +429,17 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) { type closeOnce struct { *os.File - close sync.Once - closeErr error + once sync.Once + err error } func (c *closeOnce) Close() error { - c.close.Do(func() { - c.closeErr = c.File.Close() - }) - return c.closeErr + c.once.Do(c.close) + return c.err +} + +func (c *closeOnce) close() { + c.err = c.File.Close() } // StdoutPipe returns a pipe that will be connected to the command's diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go index 06248925da2..8521bfda3f9 100644 --- a/libgo/go/os/exec/exec_test.go +++ b/libgo/go/os/exec/exec_test.go @@ -13,6 +13,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "net" "net/http" "net/http/httptest" @@ -26,7 +27,10 @@ import ( "time" ) -func helperCommand(s ...string) *exec.Cmd { +func helperCommand(t *testing.T, s ...string) *exec.Cmd { + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } cs := []string{"-test.run=TestHelperProcess", "--"} cs = append(cs, s...) cmd := exec.Command(os.Args[0], cs...) @@ -39,7 +43,7 @@ func helperCommand(s ...string) *exec.Cmd { } func TestEcho(t *testing.T) { - bs, err := helperCommand("echo", "foo bar", "baz").Output() + bs, err := helperCommand(t, "echo", "foo bar", "baz").Output() if err != nil { t.Errorf("echo: %v", err) } @@ -78,7 +82,7 @@ func TestCommandRelativeName(t *testing.T) { func TestCatStdin(t *testing.T) { // Cat, testing stdin and stdout. input := "Input string\nLine 2" - p := helperCommand("cat") + p := helperCommand(t, "cat") p.Stdin = strings.NewReader(input) bs, err := p.Output() if err != nil { @@ -92,7 +96,7 @@ func TestCatStdin(t *testing.T) { func TestCatGoodAndBadFile(t *testing.T) { // Testing combined output and error values. - bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput() + bs, err := helperCommand(t, "cat", "/bogus/file.foo", "exec_test.go").CombinedOutput() if _, ok := err.(*exec.ExitError); !ok { t.Errorf("expected *exec.ExitError from cat combined; got %T: %v", err, err) } @@ -120,7 +124,7 @@ func TestNoExistBinary(t *testing.T) { func TestExitStatus(t *testing.T) { // Test that exit values are returned correctly - cmd := helperCommand("exit", "42") + cmd := helperCommand(t, "exit", "42") err := cmd.Run() want := "exit status 42" switch runtime.GOOS { @@ -143,7 +147,7 @@ func TestPipes(t *testing.T) { } } // Cat, testing stdin and stdout. - c := helperCommand("pipetest") + c := helperCommand(t, "pipetest") stdin, err := c.StdinPipe() check("StdinPipe", err) stdout, err := c.StdoutPipe() @@ -196,7 +200,7 @@ func TestStdinClose(t *testing.T) { t.Fatalf("%s: %v", what, err) } } - cmd := helperCommand("stdinClose") + cmd := helperCommand(t, "stdinClose") stdin, err := cmd.StdinPipe() check("StdinPipe", err) // Check that we can access methods of the underlying os.File.` @@ -217,7 +221,7 @@ func TestStdinClose(t *testing.T) { // Issue 5071 func TestPipeLookPathLeak(t *testing.T) { - fd0 := numOpenFDS(t) + fd0, lsof0 := numOpenFDS(t) for i := 0; i < 4; i++ { cmd := exec.Command("something-that-does-not-exist-binary") cmd.StdoutPipe() @@ -227,19 +231,30 @@ func TestPipeLookPathLeak(t *testing.T) { t.Fatal("unexpected success") } } - fdGrowth := numOpenFDS(t) - fd0 - if fdGrowth > 2 { - t.Errorf("leaked %d fds; want ~0", fdGrowth) + for triesLeft := 3; triesLeft >= 0; triesLeft-- { + open, lsof := numOpenFDS(t) + fdGrowth := open - fd0 + if fdGrowth > 2 { + if triesLeft > 0 { + // Work around what appears to be a race with Linux's + // proc filesystem (as used by lsof). It seems to only + // be eventually consistent. Give it awhile to settle. + // See golang.org/issue/7808 + time.Sleep(100 * time.Millisecond) + continue + } + t.Errorf("leaked %d fds; want ~0; have:\n%s\noriginally:\n%s", fdGrowth, lsof, lsof0) + } + break } } -func numOpenFDS(t *testing.T) int { +func numOpenFDS(t *testing.T) (n int, lsof []byte) { lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output() if err != nil { t.Skip("skipping test; error finding or running lsof") - return 0 } - return bytes.Count(lsof, []byte("\n")) + return bytes.Count(lsof, []byte("\n")), lsof } var testedAlreadyLeaked = false @@ -305,7 +320,7 @@ func TestExtraFilesFDShuffle(t *testing.T) { // Moving this test case around within the overall tests may // affect the FDs obtained and hence the checks to catch these cases. npipes := 2 - c := helperCommand("extraFilesAndPipes", strconv.Itoa(npipes+1)) + c := helperCommand(t, "extraFilesAndPipes", strconv.Itoa(npipes+1)) rd, wr, _ := os.Pipe() defer rd.Close() if rd.Fd() != 3 { @@ -405,11 +420,15 @@ func TestExtraFiles(t *testing.T) { // Force TLS root certs to be loaded (which might involve // cgo), to make sure none of that potential C code leaks fds. - ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("Hello")) - })) + ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) + // quiet expected TLS handshake error "remote error: bad certificate" + ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + ts.StartTLS() defer ts.Close() - http.Get(ts.URL) // ignore result; just calling to force root cert loading + _, err = http.Get(ts.URL) + if err == nil { + t.Errorf("success trying to fetch %s; want an error", ts.URL) + } tf, err := ioutil.TempFile("", "") if err != nil { @@ -428,7 +447,7 @@ func TestExtraFiles(t *testing.T) { t.Fatalf("Seek: %v", err) } - c := helperCommand("read3") + c := helperCommand(t, "read3") var stdout, stderr bytes.Buffer c.Stdout = &stdout c.Stderr = &stderr @@ -471,10 +490,10 @@ func TestExtraFilesRace(t *testing.T) { for i := 0; i < 10; i++ { la := listen() - ca := helperCommand("describefiles") + ca := helperCommand(t, "describefiles") ca.ExtraFiles = []*os.File{listenerFile(la)} lb := listen() - cb := helperCommand("describefiles") + cb := helperCommand(t, "describefiles") cb.ExtraFiles = []*os.File{listenerFile(lb)} ares := make(chan string) bres := make(chan string) @@ -686,6 +705,24 @@ func TestHelperProcess(*testing.T) { } fmt.Fprintf(os.Stderr, "child: %s", response) os.Exit(0) + case "exec": + cmd := exec.Command(args[1]) + cmd.Dir = args[0] + output, err := cmd.CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "Child: %s %s", err, string(output)) + os.Exit(1) + } + fmt.Printf("%s", string(output)) + os.Exit(0) + case "lookpath": + p, err := exec.LookPath(args[0]) + if err != nil { + fmt.Fprintf(os.Stderr, "LookPath failed: %v\n", err) + os.Exit(1) + } + fmt.Print(p) + os.Exit(0) default: fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) os.Exit(2) diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go index 7b9dec7e8b5..3f895d5b3ba 100644 --- a/libgo/go/os/exec/lp_unix.go +++ b/libgo/go/os/exec/lp_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package exec diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go index 2bd5b6888d9..676be36ac77 100644 --- a/libgo/go/os/exec_plan9.go +++ b/libgo/go/os/exec_plan9.go @@ -52,10 +52,6 @@ func (p *Process) signal(sig Signal) error { if p.done() { return errors.New("os: process already finished") } - if sig == Kill { - // Special-case the kill signal since it doesn't use /proc/$pid/note. - return p.Kill() - } if e := p.writeProcFile("note", sig.String()); e != nil { return NewSyscallError("signal", e) } @@ -63,10 +59,7 @@ func (p *Process) signal(sig Signal) error { } func (p *Process) kill() error { - if e := p.writeProcFile("ctl", "kill"); e != nil { - return NewSyscallError("kill", e) - } - return nil + return p.signal(Kill) } func (p *Process) wait() (ps *ProcessState, err error) { diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go index 8a4d019d2f7..fb9d291e664 100644 --- a/libgo/go/os/exec_posix.go +++ b/libgo/go/os/exec_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package os diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go index 3c05b8f0806..1b1e3350b84 100644 --- a/libgo/go/os/exec_unix.go +++ b/libgo/go/os/exec_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package os @@ -38,6 +38,9 @@ func (p *Process) signal(sig Signal) error { if p.done() { return errors.New("os: process already finished") } + if p.Pid == -1 { + return errors.New("os: process already released") + } s, ok := sig.(syscall.Signal) if !ok { return errors.New("os: unsupported signal type") diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go index 441ad5384d7..b3466b15cc8 100644 --- a/libgo/go/os/file_posix.go +++ b/libgo/go/os/file_posix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package os diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go index 33588421dc0..7959091995f 100644 --- a/libgo/go/os/file_unix.go +++ b/libgo/go/os/file_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package os @@ -80,12 +80,7 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) { // There's a race here with fork/exec, which we are // content to live with. See ../syscall/exec_unix.go. - // On OS X 10.6, the O_CLOEXEC flag is not respected. - // On OS X 10.7, the O_CLOEXEC flag works. - // Without a cheap & reliable way to detect 10.6 vs 10.7 at - // runtime, we just always call syscall.CloseOnExec on Darwin. - // Once >=10.7 is prevalent, this extra call can removed. - if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported + if !supportsCloseOnExec { syscall.CloseOnExec(r) } @@ -188,16 +183,31 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) { return fi, err } +// Darwin and FreeBSD can't read or write 2GB+ at a time, +// even on 64-bit systems. See golang.org/issue/7812. +// Use 1GB instead of, say, 2GB-1, to keep subsequent +// reads aligned. +const ( + needsMaxRW = runtime.GOOS == "darwin" || runtime.GOOS == "freebsd" + maxRW = 1 << 30 +) + // read reads up to len(b) bytes from the File. // It returns the number of bytes read and an error, if any. func (f *File) read(b []byte) (n int, err error) { + if needsMaxRW && len(b) > maxRW { + b = b[:maxRW] + } return syscall.Read(f.fd, b) } // pread reads len(b) bytes from the File starting at byte offset off. // It returns the number of bytes read and the error, if any. -// EOF is signaled by a zero count with err set to 0. +// EOF is signaled by a zero count with err set to nil. func (f *File) pread(b []byte, off int64) (n int, err error) { + if needsMaxRW && len(b) > maxRW { + b = b[:maxRW] + } return syscall.Pread(f.fd, b, off) } @@ -205,13 +215,22 @@ func (f *File) pread(b []byte, off int64) (n int, err error) { // It returns the number of bytes written and an error, if any. func (f *File) write(b []byte) (n int, err error) { for { - m, err := syscall.Write(f.fd, b) + bcap := b + if needsMaxRW && len(bcap) > maxRW { + bcap = bcap[:maxRW] + } + m, err := syscall.Write(f.fd, bcap) n += m // If the syscall wrote some data but not all (short write) // or it returned EINTR, then assume it stopped early for // reasons that are uninteresting to the caller, and try again. - if 0 < m && m < len(b) || err == syscall.EINTR { + if 0 < m && m < len(bcap) || err == syscall.EINTR { + b = b[m:] + continue + } + + if needsMaxRW && len(bcap) != len(b) && err == nil { b = b[m:] continue } @@ -223,6 +242,9 @@ func (f *File) write(b []byte) (n int, err error) { // pwrite writes len(b) bytes to the File starting at byte offset off. // It returns the number of bytes written and an error, if any. func (f *File) pwrite(b []byte, off int64) (n int, err error) { + if needsMaxRW && len(b) > maxRW { + b = b[:maxRW] + } return syscall.Pwrite(f.fd, b, off) } diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go index 8c5ff7fca51..a72edeaee6e 100644 --- a/libgo/go/os/getwd.go +++ b/libgo/go/os/getwd.go @@ -22,7 +22,7 @@ var useSyscallwd = func(error) bool { return true } // current directory. If the current directory can be // reached via multiple paths (due to symbolic links), // Getwd may return any one of them. -func Getwd() (pwd string, err error) { +func Getwd() (dir string, err error) { // If the operating system provides a Getwd call, use it. if syscall.ImplementsGetwd { s, e := syscall.Getwd() @@ -39,22 +39,22 @@ func Getwd() (pwd string, err error) { // Clumsy but widespread kludge: // if $PWD is set and matches ".", use it. - pwd = Getenv("PWD") - if len(pwd) > 0 && pwd[0] == '/' { - d, err := Stat(pwd) + dir = Getenv("PWD") + if len(dir) > 0 && dir[0] == '/' { + d, err := Stat(dir) if err == nil && SameFile(dot, d) { - return pwd, nil + return dir, nil } } // Apply same kludge but to cached dir instead of $PWD. getwdCache.Lock() - pwd = getwdCache.dir + dir = getwdCache.dir getwdCache.Unlock() - if len(pwd) > 0 { - d, err := Stat(pwd) + if len(dir) > 0 { + d, err := Stat(dir) if err == nil && SameFile(dot, d) { - return pwd, nil + return dir, nil } } @@ -71,8 +71,8 @@ func Getwd() (pwd string, err error) { // General algorithm: find name in parent // and then find name of parent. Each iteration - // adds /name to the beginning of pwd. - pwd = "" + // adds /name to the beginning of dir. + dir = "" for parent := ".."; ; parent = "../" + parent { if len(parent) >= 1024 { // Sanity check return "", syscall.ENAMETOOLONG @@ -91,7 +91,7 @@ func Getwd() (pwd string, err error) { for _, name := range names { d, _ := Lstat(parent + "/" + name) if SameFile(d, dot) { - pwd = "/" + name + pwd + dir = "/" + name + dir goto Found } } @@ -112,8 +112,8 @@ func Getwd() (pwd string, err error) { // Save answer as hint to avoid the expensive path next time. getwdCache.Lock() - getwdCache.dir = pwd + getwdCache.dir = dir getwdCache.Unlock() - return pwd, nil + return dir, nil } diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index 0392b06c409..a34e328b814 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -494,10 +494,10 @@ func TestHardLink(t *testing.T) { } } -func TestSymLink(t *testing.T) { - // Symlinks are not supported under windows or Plan 9. - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - return +func TestSymlink(t *testing.T) { + switch runtime.GOOS { + case "windows", "plan9", "nacl": + t.Skipf("skipping on %s", runtime.GOOS) } from, to := "symlinktestfrom", "symlinktestto" Remove(from) // Just in case. @@ -557,9 +557,9 @@ func TestSymLink(t *testing.T) { } func TestLongSymlink(t *testing.T) { - // Symlinks are not supported under windows or Plan 9. - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - return + switch runtime.GOOS { + case "windows", "plan9", "nacl": + t.Skipf("skipping on %s", runtime.GOOS) } s := "0123456789abcdef" // Long, but not too long: a common limit is 255. @@ -628,6 +628,10 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) { } func TestStartProcess(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + var dir, cmd string var args []string if runtime.GOOS == "windows" { @@ -701,8 +705,10 @@ func TestFTruncate(t *testing.T) { checkSize(t, f, 1024) f.Truncate(0) checkSize(t, f, 0) - f.Write([]byte("surprise!")) - checkSize(t, f, 13+9) // wrote at offset past where hello, world was. + _, err := f.Write([]byte("surprise!")) + if err == nil { + checkSize(t, f, 13+9) // wrote at offset past where hello, world was. + } } func TestTruncate(t *testing.T) { @@ -719,8 +725,10 @@ func TestTruncate(t *testing.T) { checkSize(t, f, 1024) Truncate(f.Name(), 0) checkSize(t, f, 0) - f.Write([]byte("surprise!")) - checkSize(t, f, 13+9) // wrote at offset past where hello, world was. + _, err := f.Write([]byte("surprise!")) + if err == nil { + checkSize(t, f, 13+9) // wrote at offset past where hello, world was. + } } // Use TempDir() to make sure we're on a local file system, @@ -755,13 +763,13 @@ func TestChtimes(t *testing.T) { } postStat := st - /* Plan 9: + /* Plan 9, NaCl: Mtime is the time of the last change of content. Similarly, atime is set whenever the contents are accessed; also, it is set whenever mtime is set. */ pat := Atime(postStat) pmt := postStat.ModTime() - if !pat.Before(at) && runtime.GOOS != "plan9" { + if !pat.Before(at) && runtime.GOOS != "plan9" && runtime.GOOS != "nacl" { t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat) } @@ -963,8 +971,9 @@ func run(t *testing.T, cmd []string) string { func TestHostname(t *testing.T) { // There is no other way to fetch hostname on windows, but via winapi. // On Plan 9 it is can be taken from #c/sysname as Hostname() does. - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - return + switch runtime.GOOS { + case "windows", "plan9", "nacl": + t.Skipf("skipping on %s", runtime.GOOS) } // Check internal Hostname() against the output of /bin/hostname. @@ -1224,6 +1233,10 @@ func TestReadAtEOF(t *testing.T) { func testKillProcess(t *testing.T, processKiller func(p *Process)) { t.Skip("gccgo does not have a go command") + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + dir, err := ioutil.TempDir("", "go-build") if err != nil { t.Fatalf("Failed to create temp directory: %v", err) diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go index 27abf59826f..3af21cde9af 100644 --- a/libgo/go/os/path_test.go +++ b/libgo/go/os/path_test.go @@ -167,8 +167,9 @@ func TestRemoveAll(t *testing.T) { } func TestMkdirAllWithSymlink(t *testing.T) { - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - t.Skip("Skipping test: symlinks don't exist under Windows/Plan 9") + switch runtime.GOOS { + case "nacl", "plan9", "windows": + t.Skipf("skipping on %s", runtime.GOOS) } tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-") diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go index bdf9fe64218..0211107ddfc 100644 --- a/libgo/go/os/path_unix.go +++ b/libgo/go/os/path_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package os diff --git a/libgo/go/os/pipe_bsd.go b/libgo/go/os/pipe_bsd.go index 0ea8e4b1f83..3b81ed20f1b 100644 --- a/libgo/go/os/pipe_bsd.go +++ b/libgo/go/os/pipe_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd netbsd openbsd solaris +// +build darwin dragonfly freebsd nacl netbsd openbsd solaris package os diff --git a/libgo/go/os/signal/signal_unix.go b/libgo/go/os/signal/signal_unix.go index 80dc4304aaa..94b8ab3ddbf 100644 --- a/libgo/go/os/signal/signal_unix.go +++ b/libgo/go/os/signal/signal_unix.go @@ -2,7 +2,7 @@ // 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 windows +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows package signal diff --git a/libgo/go/os/stat_nacl.go b/libgo/go/os/stat_nacl.go new file mode 100644 index 00000000000..a503b59fa3f --- /dev/null +++ b/libgo/go/os/stat_nacl.go @@ -0,0 +1,62 @@ +// Copyright 2009 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. + +package os + +import ( + "syscall" + "time" +) + +func sameFile(fs1, fs2 *fileStat) bool { + stat1 := fs1.sys.(*syscall.Stat_t) + stat2 := fs2.sys.(*syscall.Stat_t) + return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino +} + +func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo { + fs := &fileStat{ + name: basename(name), + size: int64(st.Size), + modTime: timespecToTime(st.Mtime, st.MtimeNsec), + sys: st, + } + fs.mode = FileMode(st.Mode & 0777) + switch st.Mode & syscall.S_IFMT { + case syscall.S_IFBLK: + fs.mode |= ModeDevice + case syscall.S_IFCHR: + fs.mode |= ModeDevice | ModeCharDevice + case syscall.S_IFDIR: + fs.mode |= ModeDir + case syscall.S_IFIFO: + fs.mode |= ModeNamedPipe + case syscall.S_IFLNK: + fs.mode |= ModeSymlink + case syscall.S_IFREG: + // nothing to do + case syscall.S_IFSOCK: + fs.mode |= ModeSocket + } + if st.Mode&syscall.S_ISGID != 0 { + fs.mode |= ModeSetgid + } + if st.Mode&syscall.S_ISUID != 0 { + fs.mode |= ModeSetuid + } + if st.Mode&syscall.S_ISVTX != 0 { + fs.mode |= ModeSticky + } + return fs +} + +func timespecToTime(sec, nsec int64) time.Time { + return time.Unix(sec, nsec) +} + +// For testing. +func atime(fi FileInfo) time.Time { + st := fi.Sys().(*syscall.Stat_t) + return timespecToTime(st.Atime, st.AtimeNsec) +} diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go index 9ad2f8546b9..8ad5e218371 100644 --- a/libgo/go/os/sys_bsd.go +++ b/libgo/go/os/sys_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd netbsd openbsd +// +build darwin dragonfly freebsd nacl netbsd openbsd // os code shared between *BSD systems including OS X (Darwin) // and FreeBSD. diff --git a/libgo/go/os/sys_darwin.go b/libgo/go/os/sys_darwin.go new file mode 100644 index 00000000000..7a8330abb55 --- /dev/null +++ b/libgo/go/os/sys_darwin.go @@ -0,0 +1,31 @@ +// Copyright 2014 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. + +package os + +import "syscall" + +// supportsCloseOnExec reports whether the platform supports the +// O_CLOEXEC flag. +var supportsCloseOnExec bool + +func init() { + // Seems like kern.osreldate is veiled on latest OS X. We use + // kern.osrelease instead. + osver, err := syscall.Sysctl("kern.osrelease") + if err != nil { + return + } + var i int + for i = range osver { + if osver[i] != '.' { + continue + } + } + // The O_CLOEXEC flag was introduced in OS X 10.7 (Darwin + // 11.0.0). See http://support.apple.com/kb/HT1633. + if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' { + supportsCloseOnExec = true + } +} diff --git a/libgo/go/os/sys_freebsd.go b/libgo/go/os/sys_freebsd.go new file mode 100644 index 00000000000..273c2df1c12 --- /dev/null +++ b/libgo/go/os/sys_freebsd.go @@ -0,0 +1,23 @@ +// Copyright 2014 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. + +package os + +import "syscall" + +// supportsCloseOnExec reports whether the platform supports the +// O_CLOEXEC flag. +var supportsCloseOnExec bool + +func init() { + osrel, err := syscall.SysctlUint32("kern.osreldate") + if err != nil { + return + } + // The O_CLOEXEC flag was introduced in FreeBSD 8.3. + // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html. + if osrel >= 803000 { + supportsCloseOnExec = true + } +} diff --git a/libgo/go/os/sys_nacl.go b/libgo/go/os/sys_nacl.go new file mode 100644 index 00000000000..07907c84771 --- /dev/null +++ b/libgo/go/os/sys_nacl.go @@ -0,0 +1,9 @@ +// Copyright 2014 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. + +package os + +// supportsCloseOnExec reports whether the platform supports the +// O_CLOEXEC flag. +const supportsCloseOnExec = false diff --git a/libgo/go/os/sys_unix.go b/libgo/go/os/sys_unix.go new file mode 100644 index 00000000000..39c20dc7395 --- /dev/null +++ b/libgo/go/os/sys_unix.go @@ -0,0 +1,11 @@ +// Copyright 2014 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 dragonfly linux netbsd openbsd solaris + +package os + +// supportsCloseOnExec reports whether the platform supports the +// O_CLOEXEC flag. +const supportsCloseOnExec = true diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go index 3d84145d7f8..a9bcc103c55 100644 --- a/libgo/go/path/filepath/match.go +++ b/libgo/go/path/filepath/match.go @@ -230,7 +230,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) { // func Glob(pattern string) (matches []string, err error) { if !hasMeta(pattern) { - if _, err = os.Stat(pattern); err != nil { + if _, err = os.Lstat(pattern); err != nil { return nil, nil } return []string{pattern}, nil diff --git a/libgo/go/path/filepath/match_test.go b/libgo/go/path/filepath/match_test.go index 6a2fd927e41..9886620ade0 100644 --- a/libgo/go/path/filepath/match_test.go +++ b/libgo/go/path/filepath/match_test.go @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package filepath +package filepath_test import ( + "io/ioutil" + "os" + . "path/filepath" "runtime" "strings" "testing" @@ -154,3 +157,51 @@ func TestGlobError(t *testing.T) { t.Error("expected error for bad pattern; got none") } } + +var globSymlinkTests = []struct { + path, dest string + brokenLink bool +}{ + {"test1", "link1", false}, + {"test2", "link2", true}, +} + +func TestGlobSymlink(t *testing.T) { + switch runtime.GOOS { + case "nacl", "plan9", "windows": + t.Skipf("skipping on %s", runtime.GOOS) + } + + tmpDir, err := ioutil.TempDir("", "globsymlink") + if err != nil { + t.Fatal("creating temp dir:", err) + } + defer os.RemoveAll(tmpDir) + + for _, tt := range globSymlinkTests { + path := Join(tmpDir, tt.path) + dest := Join(tmpDir, tt.dest) + f, err := os.Create(path) + if err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + err = os.Symlink(path, dest) + if err != nil { + t.Fatal(err) + } + if tt.brokenLink { + // Break the symlink. + os.Remove(path) + } + matches, err := Glob(dest) + if err != nil { + t.Errorf("GlobSymlink error for %q: %s", dest, err) + } + if !contains(matches, dest) { + t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest) + } + } +} diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go index 65d29bf9f9d..71603cc5946 100644 --- a/libgo/go/path/filepath/path.go +++ b/libgo/go/path/filepath/path.go @@ -67,7 +67,7 @@ const ( // along with the non-.. element that precedes it. // 4. Eliminate .. elements that begin a rooted path: // that is, replace "/.." by "/" at the beginning of a path, -// assuming Separator is '/'. +// assuming Separator is '/'. // // The returned path ends in a slash only if it represents a root directory, // such as "/" on Unix or `C:\` on Windows. diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index dc87d791037..6d1139432c3 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -694,8 +694,9 @@ func simpleJoin(dir, path string) string { } func TestEvalSymlinks(t *testing.T) { - if runtime.GOOS == "plan9" { - t.Skip("Skipping test: symlinks don't exist under Plan 9") + switch runtime.GOOS { + case "nacl", "plan9": + t.Skipf("skipping on %s", runtime.GOOS) } tmpDir, err := ioutil.TempDir("", "evalsymlink") diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go index 2be675c3af1..7aba0ab5b9b 100644 --- a/libgo/go/path/filepath/path_unix.go +++ b/libgo/go/path/filepath/path_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package filepath diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 6c015ad029f..799bbea4a8a 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -15,6 +15,7 @@ import ( . "reflect" "runtime" "sort" + "strings" "sync" "testing" "time" @@ -972,6 +973,31 @@ func TestMap(t *testing.T) { } } +func TestNilMap(t *testing.T) { + var m map[string]int + mv := ValueOf(m) + keys := mv.MapKeys() + if len(keys) != 0 { + t.Errorf(">0 keys for nil map: %v", keys) + } + + // Check that value for missing key is zero. + x := mv.MapIndex(ValueOf("hello")) + if x.Kind() != Invalid { + t.Errorf("m.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x) + } + + // Check big value too. + var mbig map[string][10 << 20]byte + x = ValueOf(mbig).MapIndex(ValueOf("hello")) + if x.Kind() != Invalid { + t.Errorf("mbig.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x) + } + + // Test that deletes from a nil map succeed. + mv.SetMapIndex(ValueOf("hi"), Value{}) +} + func TestChan(t *testing.T) { for loop := 0; loop < 2; loop++ { var c chan int @@ -1523,6 +1549,23 @@ func TestMakeFuncInterface(t *testing.T) { } } +func TestMakeFuncVariadic(t *testing.T) { + // Test that variadic arguments are packed into a slice and passed as last arg + fn := func(_ int, is ...int) []int { return nil } + fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] }) + ValueOf(&fn).Elem().Set(fv) + + r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } + + r = fv.CallSlice([]Value{ValueOf(1), ValueOf([]int{2, 3})})[0].Interface().([]int) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } +} + type Point struct { x, y int } @@ -3723,3 +3766,107 @@ func TestBigZero(t *testing.T) { } } } + +func TestFieldByIndexNil(t *testing.T) { + type P struct { + F int + } + type T struct { + *P + } + v := ValueOf(T{}) + + v.FieldByName("P") // should be fine + + defer func() { + if err := recover(); err == nil { + t.Fatalf("no error") + } else if !strings.Contains(fmt.Sprint(err), "nil pointer to embedded struct") { + t.Fatalf(`err=%q, wanted error containing "nil pointer to embedded struct"`, err) + } + }() + v.FieldByName("F") // should panic + + t.Fatalf("did not panic") +} + +// Given +// type Outer struct { +// *Inner +// ... +// } +// the compiler generates the implementation of (*Outer).M dispatching to the embedded Inner. +// The implementation is logically: +// func (p *Outer) M() { +// (p.Inner).M() +// } +// but since the only change here is the replacement of one pointer receiver with another, +// the actual generated code overwrites the original receiver with the p.Inner pointer and +// then jumps to the M method expecting the *Inner receiver. +// +// During reflect.Value.Call, we create an argument frame and the associated data structures +// to describe it to the garbage collector, populate the frame, call reflect.call to +// run a function call using that frame, and then copy the results back out of the frame. +// The reflect.call function does a memmove of the frame structure onto the +// stack (to set up the inputs), runs the call, and the memmoves the stack back to +// the frame structure (to preserve the outputs). +// +// Originally reflect.call did not distinguish inputs from outputs: both memmoves +// were for the full stack frame. However, in the case where the called function was +// one of these wrappers, the rewritten receiver is almost certainly a different type +// than the original receiver. This is not a problem on the stack, where we use the +// program counter to determine the type information and understand that +// during (*Outer).M the receiver is an *Outer while during (*Inner).M the receiver in the same +// memory word is now an *Inner. But in the statically typed argument frame created +// by reflect, the receiver is always an *Outer. Copying the modified receiver pointer +// off the stack into the frame will store an *Inner there, and then if a garbage collection +// happens to scan that argument frame before it is discarded, it will scan the *Inner +// memory as if it were an *Outer. If the two have different memory layouts, the +// collection will intepret the memory incorrectly. +// +// One such possible incorrect interpretation is to treat two arbitrary memory words +// (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting +// an interface requires dereferencing the itab word, the misinterpretation will try to +// deference Inner.P1, causing a crash during garbage collection. +// +// This came up in a real program in issue 7725. + +type Outer struct { + *Inner + R io.Reader +} + +type Inner struct { + X *Outer + P1 uintptr + P2 uintptr +} + +func (pi *Inner) M() { + // Clear references to pi so that the only way the + // garbage collection will find the pointer is in the + // argument frame, typed as a *Outer. + pi.X.Inner = nil + + // Set up an interface value that will cause a crash. + // P1 = 1 is a non-zero, so the interface looks non-nil. + // P2 = pi ensures that the data word points into the + // allocated heap; if not the collection skips the interface + // value as irrelevant, without dereferencing P1. + pi.P1 = 1 + pi.P2 = uintptr(unsafe.Pointer(pi)) +} + +func TestCallMethodJump(t *testing.T) { + // In reflect.Value.Call, trigger a garbage collection after reflect.call + // returns but before the args frame has been discarded. + // This is a little clumsy but makes the failure repeatable. + *CallGC = true + + p := &Outer{Inner: new(Inner)} + p.Inner.X = p + ValueOf(p).Method(0).Call(nil) + + // Stop garbage collecting during reflect.call. + *CallGC = false +} diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go index cd8cf2cf2c9..0778ad37f5c 100644 --- a/libgo/go/reflect/export_test.go +++ b/libgo/go/reflect/export_test.go @@ -16,3 +16,4 @@ func IsRO(v Value) bool { } var ArrayOf = arrayOf +var CallGC = &callGC diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index b248743de70..a46e1d86497 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -113,7 +113,7 @@ func makeMethodValue(op string, v Value) Value { // Cause panic if method is not appropriate. // The panic would still happen during the call if we omit this, // but we want Interface() and other operations to fail early. - t, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift) + _, t, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift) fv := &makeFuncImpl{ code: code, @@ -167,17 +167,9 @@ func (c *makeFuncImpl) call(in []Value) []Value { if c.method == -1 { return c.fn(in) } else if c.method == -2 { - if c.typ.IsVariadic() { - return c.rcvr.CallSlice(in) - } else { - return c.rcvr.Call(in) - } + return c.rcvr.Call(in) } else { m := c.rcvr.Method(c.method) - if c.typ.IsVariadic() { - return m.CallSlice(in) - } else { - return m.Call(in) - } + return m.Call(in) } } diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index f8e2c59b614..74cf2946a01 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -16,6 +16,7 @@ package reflect import ( + "runtime" "strconv" "sync" "unsafe" @@ -1519,6 +1520,13 @@ func MapOf(key, elem Type) Type { mt.uncommonType = nil mt.ptrToThis = nil mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0]) + // mt.gc = unsafe.Pointer(&ptrGC{ + // width: unsafe.Sizeof(uintptr(0)), + // op: _GC_PTR, + // off: 0, + // elemgc: mt.hmap.gc, + // end: _GC_END, + // }) // INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues // fail when mt.gc is wrong. @@ -1551,6 +1559,10 @@ func bucketOf(ktyp, etyp *rtype) *rtype { gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow offset += ptrsize + if runtime.GOARCH == "amd64p32" { + offset += 4 + } + // keys if ktyp.kind&kindNoPointers == 0 { gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size) diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 64081b9ea51..cac083304ca 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -425,6 +425,8 @@ func (v Value) CallSlice(in []Value) []Value { return v.call("CallSlice", in) } +var callGC bool // for testing; see TestCallMethodJump + var makeFuncStubFn = makeFuncStub var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn)) @@ -437,9 +439,8 @@ func (v Value) call(op string, in []Value) []Value { rcvrtype *rtype ) if v.flag&flagMethod != 0 { - rcvrtype = t rcvr = v - t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift) + rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift) } else if v.flag&flagIndir != 0 { fn = *(*unsafe.Pointer)(v.ptr) } else { @@ -450,17 +451,6 @@ func (v Value) call(op string, in []Value) []Value { panic("reflect.Value.Call: call of nil function") } - // If target is makeFuncStub, short circuit the unpack onto stack / - // pack back into []Value for the args and return values. Just do the - // call directly. - // We need to do this here because otherwise we have a situation where - // reflect.callXX calls makeFuncStub, neither of which knows the - // layout of the args. That's bad for precise gc & stack copying. - x := (*makeFuncImpl)(fn) - if x.code == makeFuncStubCode { - return x.call(in) - } - isSlice := op == "CallSlice" n := t.NumIn() if isSlice { @@ -518,6 +508,17 @@ func (v Value) call(op string, in []Value) []Value { } nout := t.NumOut() + // If target is makeFuncStub, short circuit the unpack onto stack / + // pack back into []Value for the args and return values. Just do the + // call directly. + // We need to do this here because otherwise we have a situation where + // reflect.callXX calls makeFuncStub, neither of which knows the + // layout of the args. That's bad for precise gc & stack copying. + x := (*makeFuncImpl)(fn) + if x.code == makeFuncStubCode { + return x.call(in) + } + if v.flag&flagMethod != 0 { nin++ } @@ -575,6 +576,11 @@ func (v Value) call(op string, in []Value) []Value { call(t, fn, v.flag&flagMethod != 0, firstPointer, pp, pr) + // For testing; see TestCallMethodJump. + if callGC { + runtime.GC() + } + return ret } @@ -582,9 +588,10 @@ func (v Value) call(op string, in []Value) []Value { // described by v. The Value v may or may not have the // flagMethod bit set, so the kind cached in v.flag should // not be used. +// The return value rcvrtype gives the method's actual receiver type. // The return value t gives the method type signature (without the receiver). // The return value fn is a pointer to the method code. -func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Pointer) { +func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) { i := methodIndex if v.typ.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(v.typ)) @@ -599,9 +606,11 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po if iface.itab == nil { panic("reflect: " + op + " of method on nil interface value") } + rcvrtype = iface.itab.typ fn = unsafe.Pointer(&iface.itab.fun[i]) t = m.typ } else { + rcvrtype = v.typ ut := v.typ.uncommon() if ut == nil || i < 0 || i >= len(ut.methods) { panic("reflect: internal error: invalid method index") @@ -786,7 +795,10 @@ func (v Value) FieldByIndex(index []int) Value { v.mustBe(Struct) for i, x := range index { if i > 0 { - if v.Kind() == Ptr && v.Elem().Kind() == Struct { + if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct { + if v.IsNil() { + panic("reflect: indirection through nil pointer to embedded struct") + } v = v.Elem() } } @@ -1516,6 +1528,7 @@ func (v Value) SetCap(n int) { // SetMapIndex sets the value associated with key in the map v to val. // It panics if v's Kind is not Map. // If val is the zero Value, SetMapIndex deletes the key from the map. +// Otherwise if v holds a nil map, SetMapIndex will panic. // As in Go, key's value must be assignable to the map's key type, // and val's value must be assignable to the map's value type. func (v Value) SetMapIndex(key, val Value) { @@ -2198,7 +2211,7 @@ func Zero(typ Type) Value { } // New returns a Value representing a pointer to a new zero value -// for the specified type. That is, the returned Value's Type is PtrTo(t). +// for the specified type. That is, the returned Value's Type is PtrTo(typ). func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go index e914a7ccb48..301a1dfcd83 100644 --- a/libgo/go/regexp/all_test.go +++ b/libgo/go/regexp/all_test.go @@ -473,6 +473,11 @@ func TestSplit(t *testing.T) { } } +// This ran out of stack before issue 7608 was fixed. +func TestOnePassCutoff(t *testing.T) { + MustCompile(`^(?:x{1,1000}){1,1000}$`) +} + func BenchmarkLiteral(b *testing.B) { x := strings.Repeat("x", 50) + "y" b.StopTimer() @@ -578,3 +583,63 @@ func BenchmarkAnchoredLongMatch(b *testing.B) { re.Match(x) } } + +func BenchmarkOnePassShortA(b *testing.B) { + b.StopTimer() + x := []byte("abcddddddeeeededd") + re := MustCompile("^.bc(d|e)*$") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkNotOnePassShortA(b *testing.B) { + b.StopTimer() + x := []byte("abcddddddeeeededd") + re := MustCompile(".bc(d|e)*$") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkOnePassShortB(b *testing.B) { + b.StopTimer() + x := []byte("abcddddddeeeededd") + re := MustCompile("^.bc(?:d|e)*$") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkNotOnePassShortB(b *testing.B) { + b.StopTimer() + x := []byte("abcddddddeeeededd") + re := MustCompile(".bc(?:d|e)*$") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkOnePassLongPrefix(b *testing.B) { + b.StopTimer() + x := []byte("abcdefghijklmnopqrstuvwxyz") + re := MustCompile("^abcdefghijklmnopqrstuvwxyz.*$") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkOnePassLongNotPrefix(b *testing.B) { + b.StopTimer() + x := []byte("abcdefghijklmnopqrstuvwxyz") + re := MustCompile("^.bcdefghijklmnopqrstuvwxyz.*$") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} diff --git a/libgo/go/regexp/exec.go b/libgo/go/regexp/exec.go index 333ca255428..c4cb201f642 100644 --- a/libgo/go/regexp/exec.go +++ b/libgo/go/regexp/exec.go @@ -37,6 +37,7 @@ type thread struct { type machine struct { re *Regexp // corresponding Regexp p *syntax.Prog // compiled program + op *onePassProg // compiled onepass program, or notOnePass q0, q1 queue // two queues for runq, nextq pool []*thread // pool of available threads matched bool // whether a match was found @@ -66,8 +67,8 @@ func (m *machine) newInputReader(r io.RuneReader) input { } // progMachine returns a new machine running the prog p. -func progMachine(p *syntax.Prog) *machine { - m := &machine{p: p} +func progMachine(p *syntax.Prog, op *onePassProg) *machine { + m := &machine{p: p, op: op} n := len(m.p.Inst) m.q0 = queue{make([]uint32, n), make([]entry, 0, n)} m.q1 = queue{make([]uint32, n), make([]entry, 0, n)} @@ -312,6 +313,105 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty return t } +// onepass runs the machine over the input starting at pos. +// It reports whether a match was found. +// If so, m.matchcap holds the submatch information. +func (m *machine) onepass(i input, pos int) bool { + startCond := m.re.cond + if startCond == ^syntax.EmptyOp(0) { // impossible + return false + } + m.matched = false + for i := range m.matchcap { + m.matchcap[i] = -1 + } + r, r1 := endOfText, endOfText + width, width1 := 0, 0 + r, width = i.step(pos) + if r != endOfText { + r1, width1 = i.step(pos + width) + } + var flag syntax.EmptyOp + if pos == 0 { + flag = syntax.EmptyOpContext(-1, r) + } else { + flag = i.context(pos) + } + pc := m.op.Start + inst := m.op.Inst[pc] + // If there is a simple literal prefix, skip over it. + if pos == 0 && syntax.EmptyOp(inst.Arg)&^flag == 0 && + len(m.re.prefix) > 0 && i.canCheckPrefix() { + // Match requires literal prefix; fast search for it. + if i.hasPrefix(m.re) { + pos += len(m.re.prefix) + r, width = i.step(pos) + r1, width1 = i.step(pos + width) + flag = i.context(pos) + pc = int(m.re.prefixEnd) + } else { + return m.matched + } + } + for { + inst = m.op.Inst[pc] + pc = int(inst.Out) + switch inst.Op { + default: + panic("bad inst") + case syntax.InstMatch: + m.matched = true + if len(m.matchcap) > 0 { + m.matchcap[0] = 0 + m.matchcap[1] = pos + } + return m.matched + case syntax.InstRune: + if !inst.MatchRune(r) { + return m.matched + } + case syntax.InstRune1: + if r != inst.Rune[0] { + return m.matched + } + case syntax.InstRuneAny: + // Nothing + case syntax.InstRuneAnyNotNL: + if r == '\n' { + return m.matched + } + // peek at the input rune to see which branch of the Alt to take + case syntax.InstAlt, syntax.InstAltMatch: + pc = int(onePassNext(&inst, r)) + continue + case syntax.InstFail: + return m.matched + case syntax.InstNop: + continue + case syntax.InstEmptyWidth: + if syntax.EmptyOp(inst.Arg)&^flag != 0 { + return m.matched + } + continue + case syntax.InstCapture: + if int(inst.Arg) < len(m.matchcap) { + m.matchcap[inst.Arg] = pos + } + continue + } + if width == 0 { + break + } + flag = syntax.EmptyOpContext(r, r1) + pos += width + r, width = r1, width1 + if r != endOfText { + r1, width1 = i.step(pos + width) + } + } + return m.matched +} + // empty is a non-nil 0-element slice, // so doExecute can avoid an allocation // when 0 captures are requested from a successful match. @@ -329,16 +429,23 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i } else { i = m.newInputString(s) } - m.init(ncap) - if !m.match(i, pos) { - re.put(m) - return nil + if m.op != notOnePass { + if !m.onepass(i, pos) { + re.put(m) + return nil + } + } else { + m.init(ncap) + if !m.match(i, pos) { + re.put(m) + return nil + } } if ncap == 0 { re.put(m) return empty // empty but not nil } - cap := make([]int, ncap) + cap := make([]int, len(m.matchcap)) copy(cap, m.matchcap) re.put(m) return cap diff --git a/libgo/go/regexp/onepass.go b/libgo/go/regexp/onepass.go new file mode 100644 index 00000000000..501fb28af66 --- /dev/null +++ b/libgo/go/regexp/onepass.go @@ -0,0 +1,582 @@ +// Copyright 2014 The Go Authors. All rights reserved. + +package regexp + +import ( + "bytes" + "regexp/syntax" + "sort" + "unicode" +) + +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// "One-pass" regexp execution. +// Some regexps can be analyzed to determine that they never need +// backtracking: they are guaranteed to run in one pass over the string +// without bothering to save all the usual NFA state. +// Detect those and execute them more quickly. + +// A onePassProg is a compiled one-pass regular expression program. +// It is the same as syntax.Prog except for the use of onePassInst. +type onePassProg struct { + Inst []onePassInst + Start int // index of start instruction + NumCap int // number of InstCapture insts in re +} + +// A onePassInst is a single instruction in a one-pass regular expression program. +// It is the same as syntax.Inst except for the new 'Next' field. +type onePassInst struct { + syntax.Inst + Next []uint32 +} + +// OnePassPrefix returns a literal string that all matches for the +// regexp must start with. Complete is true if the prefix +// is the entire match. Pc is the index of the last rune instruction +// in the string. The OnePassPrefix skips over the mandatory +// EmptyBeginText +func onePassPrefix(p *syntax.Prog) (prefix string, complete bool, pc uint32) { + i := &p.Inst[p.Start] + if i.Op != syntax.InstEmptyWidth || (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText == 0 { + return "", i.Op == syntax.InstMatch, uint32(p.Start) + } + pc = i.Out + i = &p.Inst[pc] + for i.Op == syntax.InstNop { + pc = i.Out + i = &p.Inst[pc] + } + // Avoid allocation of buffer if prefix is empty. + if iop(i) != syntax.InstRune || len(i.Rune) != 1 { + return "", i.Op == syntax.InstMatch, uint32(p.Start) + } + + // Have prefix; gather characters. + var buf bytes.Buffer + for iop(i) == syntax.InstRune && len(i.Rune) == 1 && syntax.Flags(i.Arg)&syntax.FoldCase == 0 { + buf.WriteRune(i.Rune[0]) + pc, i = i.Out, &p.Inst[i.Out] + } + return buf.String(), i.Op == syntax.InstEmptyWidth && (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText != 0, pc +} + +// OnePassNext selects the next actionable state of the prog, based on the input character. +// It should only be called when i.Op == InstAlt or InstAltMatch, and from the one-pass machine. +// One of the alternates may ultimately lead without input to end of line. If the instruction +// is InstAltMatch the path to the InstMatch is in i.Out, the normal node in i.Next. +func onePassNext(i *onePassInst, r rune) uint32 { + next := i.MatchRunePos(r) + if next >= 0 { + return i.Next[next] + } + if i.Op == syntax.InstAltMatch { + return i.Out + } + return 0 +} + +func iop(i *syntax.Inst) syntax.InstOp { + op := i.Op + switch op { + case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL: + op = syntax.InstRune + } + return op +} + +// Sparse Array implementation is used as a queueOnePass. +type queueOnePass struct { + sparse []uint32 + dense []uint32 + size, nextIndex uint32 +} + +func (q *queueOnePass) empty() bool { + return q.nextIndex >= q.size +} + +func (q *queueOnePass) next() (n uint32) { + n = q.dense[q.nextIndex] + q.nextIndex++ + return +} + +func (q *queueOnePass) clear() { + q.size = 0 + q.nextIndex = 0 +} + +func (q *queueOnePass) reset() { + q.nextIndex = 0 +} + +func (q *queueOnePass) contains(u uint32) bool { + if u >= uint32(len(q.sparse)) { + return false + } + return q.sparse[u] < q.size && q.dense[q.sparse[u]] == u +} + +func (q *queueOnePass) insert(u uint32) { + if !q.contains(u) { + q.insertNew(u) + } +} + +func (q *queueOnePass) insertNew(u uint32) { + if u >= uint32(len(q.sparse)) { + return + } + q.sparse[u] = q.size + q.dense[q.size] = u + q.size++ +} + +func newQueue(size int) (q *queueOnePass) { + return &queueOnePass{ + sparse: make([]uint32, size), + dense: make([]uint32, size), + } +} + +// mergeRuneSets merges two non-intersecting runesets, and returns the merged result, +// and a NextIp array. The idea is that if a rune matches the OnePassRunes at index +// i, NextIp[i/2] is the target. If the input sets intersect, an empty runeset and a +// NextIp array with the single element mergeFailed is returned. +// The code assumes that both inputs contain ordered and non-intersecting rune pairs. +const mergeFailed = uint32(0xffffffff) + +var ( + noRune = []rune{} + noNext = []uint32{mergeFailed} +) + +func mergeRuneSets(leftRunes, rightRunes *[]rune, leftPC, rightPC uint32) ([]rune, []uint32) { + leftLen := len(*leftRunes) + rightLen := len(*rightRunes) + if leftLen&0x1 != 0 || rightLen&0x1 != 0 { + panic("mergeRuneSets odd length []rune") + } + var ( + lx, rx int + ) + merged := make([]rune, 0) + next := make([]uint32, 0) + ok := true + defer func() { + if !ok { + merged = nil + next = nil + } + }() + + ix := -1 + extend := func(newLow *int, newArray *[]rune, pc uint32) bool { + if ix > 0 && (*newArray)[*newLow] <= merged[ix] { + return false + } + merged = append(merged, (*newArray)[*newLow], (*newArray)[*newLow+1]) + *newLow += 2 + ix += 2 + next = append(next, pc) + return true + } + + for lx < leftLen || rx < rightLen { + switch { + case rx >= rightLen: + ok = extend(&lx, leftRunes, leftPC) + case lx >= leftLen: + ok = extend(&rx, rightRunes, rightPC) + case (*rightRunes)[rx] < (*leftRunes)[lx]: + ok = extend(&rx, rightRunes, rightPC) + default: + ok = extend(&lx, leftRunes, leftPC) + } + if !ok { + return noRune, noNext + } + } + return merged, next +} + +// cleanupOnePass drops working memory, and restores certain shortcut instructions. +func cleanupOnePass(prog *onePassProg, original *syntax.Prog) { + for ix, instOriginal := range original.Inst { + switch instOriginal.Op { + case syntax.InstAlt, syntax.InstAltMatch, syntax.InstRune: + case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop, syntax.InstMatch, syntax.InstFail: + prog.Inst[ix].Next = nil + case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL: + prog.Inst[ix].Next = nil + prog.Inst[ix] = onePassInst{Inst: instOriginal} + } + } +} + +// onePassCopy creates a copy of the original Prog, as we'll be modifying it +func onePassCopy(prog *syntax.Prog) *onePassProg { + p := &onePassProg{ + Start: prog.Start, + NumCap: prog.NumCap, + } + for _, inst := range prog.Inst { + p.Inst = append(p.Inst, onePassInst{Inst: inst}) + } + + // rewrites one or more common Prog constructs that enable some otherwise + // non-onepass Progs to be onepass. A:BD (for example) means an InstAlt at + // ip A, that points to ips B & C. + // A:BC + B:DA => A:BC + B:CD + // A:BC + B:DC => A:DC + B:DC + for pc := range p.Inst { + switch p.Inst[pc].Op { + default: + continue + case syntax.InstAlt, syntax.InstAltMatch: + // A:Bx + B:Ay + p_A_Other := &p.Inst[pc].Out + p_A_Alt := &p.Inst[pc].Arg + // make sure a target is another Alt + instAlt := p.Inst[*p_A_Alt] + if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) { + p_A_Alt, p_A_Other = p_A_Other, p_A_Alt + instAlt = p.Inst[*p_A_Alt] + if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) { + continue + } + } + instOther := p.Inst[*p_A_Other] + // Analyzing both legs pointing to Alts is for another day + if instOther.Op == syntax.InstAlt || instOther.Op == syntax.InstAltMatch { + // too complicated + continue + } + // simple empty transition loop + // A:BC + B:DA => A:BC + B:DC + p_B_Alt := &p.Inst[*p_A_Alt].Out + p_B_Other := &p.Inst[*p_A_Alt].Arg + patch := false + if instAlt.Out == uint32(pc) { + patch = true + } else if instAlt.Arg == uint32(pc) { + patch = true + p_B_Alt, p_B_Other = p_B_Other, p_B_Alt + } + if patch { + *p_B_Alt = *p_A_Other + } + + // empty transition to common target + // A:BC + B:DC => A:DC + B:DC + if *p_A_Other == *p_B_Alt { + *p_A_Alt = *p_B_Other + } + } + } + return p +} + +// runeSlice exists to permit sorting the case-folded rune sets. +type runeSlice []rune + +func (p runeSlice) Len() int { return len(p) } +func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] } +func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// Sort is a convenience method. +func (p runeSlice) Sort() { + sort.Sort(p) +} + +var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune} +var anyRune = []rune{0, unicode.MaxRune} + +// makeOnePass creates a onepass Prog, if possible. It is possible if at any alt, +// the match engine can always tell which branch to take. The routine may modify +// p if it is turned into a onepass Prog. If it isn't possible for this to be a +// onepass Prog, the Prog notOnePass is returned. makeOnePass is recursive +// to the size of the Prog. +func makeOnePass(p *onePassProg) *onePassProg { + // If the machine is very long, it's not worth the time to check if we can use one pass. + if len(p.Inst) >= 1000 { + return notOnePass + } + + var ( + instQueue = newQueue(len(p.Inst)) + visitQueue = newQueue(len(p.Inst)) + build func(uint32, *queueOnePass) + check func(uint32, map[uint32]bool) bool + onePassRunes = make([][]rune, len(p.Inst)) + ) + build = func(pc uint32, q *queueOnePass) { + if q.contains(pc) { + return + } + inst := p.Inst[pc] + switch inst.Op { + case syntax.InstAlt, syntax.InstAltMatch: + q.insert(inst.Out) + build(inst.Out, q) + q.insert(inst.Arg) + case syntax.InstMatch, syntax.InstFail: + default: + q.insert(inst.Out) + } + } + + // check that paths from Alt instructions are unambiguous, and rebuild the new + // program as a onepass program + check = func(pc uint32, m map[uint32]bool) (ok bool) { + ok = true + inst := &p.Inst[pc] + if visitQueue.contains(pc) { + return + } + visitQueue.insert(pc) + switch inst.Op { + case syntax.InstAlt, syntax.InstAltMatch: + ok = check(inst.Out, m) && check(inst.Arg, m) + // check no-input paths to InstMatch + matchOut := m[inst.Out] + matchArg := m[inst.Arg] + if matchOut && matchArg { + ok = false + break + } + // Match on empty goes in inst.Out + if matchArg { + inst.Out, inst.Arg = inst.Arg, inst.Out + matchOut, matchArg = matchArg, matchOut + } + if matchOut { + m[pc] = true + inst.Op = syntax.InstAltMatch + } + + // build a dispatch operator from the two legs of the alt. + onePassRunes[pc], inst.Next = mergeRuneSets( + &onePassRunes[inst.Out], &onePassRunes[inst.Arg], inst.Out, inst.Arg) + if len(inst.Next) > 0 && inst.Next[0] == mergeFailed { + ok = false + break + } + case syntax.InstCapture, syntax.InstNop: + ok = check(inst.Out, m) + m[pc] = m[inst.Out] + // pass matching runes back through these no-ops. + onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...) + inst.Next = []uint32{} + for i := len(onePassRunes[pc]) / 2; i >= 0; i-- { + inst.Next = append(inst.Next, inst.Out) + } + case syntax.InstEmptyWidth: + ok = check(inst.Out, m) + m[pc] = m[inst.Out] + onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...) + inst.Next = []uint32{} + for i := len(onePassRunes[pc]) / 2; i >= 0; i-- { + inst.Next = append(inst.Next, inst.Out) + } + case syntax.InstMatch, syntax.InstFail: + m[pc] = inst.Op == syntax.InstMatch + break + case syntax.InstRune: + ok = check(inst.Out, m) + m[pc] = false + if len(inst.Next) > 0 { + break + } + if len(inst.Rune) == 0 { + onePassRunes[pc] = []rune{} + inst.Next = []uint32{inst.Out} + break + } + runes := make([]rune, 0) + if len(inst.Rune) == 1 && syntax.Flags(inst.Arg)&syntax.FoldCase != 0 { + r0 := inst.Rune[0] + runes = append(runes, r0, r0) + for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) { + runes = append(runes, r1, r1) + } + sort.Sort(runeSlice(runes)) + } else { + runes = append(runes, inst.Rune...) + } + onePassRunes[pc] = runes + inst.Next = []uint32{} + for i := len(onePassRunes[pc]) / 2; i >= 0; i-- { + inst.Next = append(inst.Next, inst.Out) + } + inst.Op = syntax.InstRune + case syntax.InstRune1: + ok = check(inst.Out, m) + m[pc] = false + if len(inst.Next) > 0 { + break + } + runes := []rune{} + // expand case-folded runes + if syntax.Flags(inst.Arg)&syntax.FoldCase != 0 { + r0 := inst.Rune[0] + runes = append(runes, r0, r0) + for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) { + runes = append(runes, r1, r1) + } + sort.Sort(runeSlice(runes)) + } else { + runes = append(runes, inst.Rune[0], inst.Rune[0]) + } + onePassRunes[pc] = runes + inst.Next = []uint32{} + for i := len(onePassRunes[pc]) / 2; i >= 0; i-- { + inst.Next = append(inst.Next, inst.Out) + } + inst.Op = syntax.InstRune + case syntax.InstRuneAny: + ok = check(inst.Out, m) + m[pc] = false + if len(inst.Next) > 0 { + break + } + onePassRunes[pc] = append([]rune{}, anyRune...) + inst.Next = []uint32{inst.Out} + case syntax.InstRuneAnyNotNL: + ok = check(inst.Out, m) + m[pc] = false + if len(inst.Next) > 0 { + break + } + onePassRunes[pc] = append([]rune{}, anyRuneNotNL...) + inst.Next = []uint32{} + for i := len(onePassRunes[pc]) / 2; i >= 0; i-- { + inst.Next = append(inst.Next, inst.Out) + } + } + return + } + + instQueue.clear() + instQueue.insert(uint32(p.Start)) + m := make(map[uint32]bool, len(p.Inst)) + for !instQueue.empty() { + pc := instQueue.next() + inst := p.Inst[pc] + visitQueue.clear() + if !check(uint32(pc), m) { + p = notOnePass + break + } + switch inst.Op { + case syntax.InstAlt, syntax.InstAltMatch: + instQueue.insert(inst.Out) + instQueue.insert(inst.Arg) + case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop: + instQueue.insert(inst.Out) + case syntax.InstMatch: + case syntax.InstFail: + case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL: + default: + } + } + if p != notOnePass { + for i, _ := range p.Inst { + p.Inst[i].Rune = onePassRunes[i] + } + } + return p +} + +// walk visits each Inst in the prog once, and applies the argument +// function(ip, next), in pre-order. +func walk(prog *syntax.Prog, funcs ...func(ip, next uint32)) { + var walk1 func(uint32) + progQueue := newQueue(len(prog.Inst)) + walk1 = func(ip uint32) { + if progQueue.contains(ip) { + return + } + progQueue.insert(ip) + inst := prog.Inst[ip] + switch inst.Op { + case syntax.InstAlt, syntax.InstAltMatch: + for _, f := range funcs { + f(ip, inst.Out) + f(ip, inst.Arg) + } + walk1(inst.Out) + walk1(inst.Arg) + default: + for _, f := range funcs { + f(ip, inst.Out) + } + walk1(inst.Out) + } + } + walk1(uint32(prog.Start)) +} + +// find returns the Insts that match the argument predicate function +func find(prog *syntax.Prog, f func(*syntax.Prog, int) bool) (matches []uint32) { + matches = []uint32{} + + for ip := range prog.Inst { + if f(prog, ip) { + matches = append(matches, uint32(ip)) + } + } + return +} + +var notOnePass *onePassProg = nil + +// compileOnePass returns a new *syntax.Prog suitable for onePass execution if the original Prog +// can be recharacterized as a one-pass regexp program, or syntax.notOnePass if the +// Prog cannot be converted. For a one pass prog, the fundamental condition that must +// be true is: at any InstAlt, there must be no ambiguity about what branch to take. +func compileOnePass(prog *syntax.Prog) (p *onePassProg) { + if prog.Start == 0 { + return notOnePass + } + // onepass regexp is anchored + if prog.Inst[prog.Start].Op != syntax.InstEmptyWidth || + syntax.EmptyOp(prog.Inst[prog.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText { + return notOnePass + } + // every instruction leading to InstMatch must be EmptyEndText + for _, inst := range prog.Inst { + opOut := prog.Inst[inst.Out].Op + switch inst.Op { + default: + if opOut == syntax.InstMatch { + return notOnePass + } + case syntax.InstAlt, syntax.InstAltMatch: + if opOut == syntax.InstMatch || prog.Inst[inst.Arg].Op == syntax.InstMatch { + return notOnePass + } + case syntax.InstEmptyWidth: + if opOut == syntax.InstMatch { + if syntax.EmptyOp(inst.Arg)&syntax.EmptyEndText == syntax.EmptyEndText { + continue + } + return notOnePass + } + } + } + // Creates a slightly optimized copy of the original Prog + // that cleans up some Prog idioms that block valid onepass programs + p = onePassCopy(prog) + + // checkAmbiguity on InstAlts, build onepass Prog if possible + p = makeOnePass(p) + + if p != notOnePass { + cleanupOnePass(p, prog) + } + return p +} diff --git a/libgo/go/regexp/onepass_test.go b/libgo/go/regexp/onepass_test.go new file mode 100644 index 00000000000..7b2beea67ff --- /dev/null +++ b/libgo/go/regexp/onepass_test.go @@ -0,0 +1,208 @@ +// Copyright 2014 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. + +package regexp + +import ( + "reflect" + "regexp/syntax" + "testing" +) + +var runeMergeTests = []struct { + left, right, merged []rune + next []uint32 + leftPC, rightPC uint32 +}{ + { + // empty rhs + []rune{69, 69}, + []rune{}, + []rune{69, 69}, + []uint32{1}, + 1, 2, + }, + { + // identical runes, identical targets + []rune{69, 69}, + []rune{69, 69}, + []rune{}, + []uint32{mergeFailed}, + 1, 1, + }, + { + // identical runes, different targets + []rune{69, 69}, + []rune{69, 69}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, + { + // append right-first + []rune{69, 69}, + []rune{71, 71}, + []rune{69, 69, 71, 71}, + []uint32{1, 2}, + 1, 2, + }, + { + // append, left-first + []rune{71, 71}, + []rune{69, 69}, + []rune{69, 69, 71, 71}, + []uint32{2, 1}, + 1, 2, + }, + { + // successful interleave + []rune{60, 60, 71, 71, 101, 101}, + []rune{69, 69, 88, 88}, + []rune{60, 60, 69, 69, 71, 71, 88, 88, 101, 101}, + []uint32{1, 2, 1, 2, 1}, + 1, 2, + }, + { + // left surrounds right + []rune{69, 74}, + []rune{71, 71}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, + { + // right surrounds left + []rune{69, 74}, + []rune{68, 75}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, + { + // overlap at interval begin + []rune{69, 74}, + []rune{74, 75}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, + { + // overlap ar interval end + []rune{69, 74}, + []rune{65, 69}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, + { + // overlap from above + []rune{69, 74}, + []rune{71, 74}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, + { + // overlap from below + []rune{69, 74}, + []rune{65, 71}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, + { + // out of order []rune + []rune{69, 74, 60, 65}, + []rune{66, 67}, + []rune{}, + []uint32{mergeFailed}, + 1, 2, + }, +} + +func TestMergeRuneSet(t *testing.T) { + for ix, test := range runeMergeTests { + merged, next := mergeRuneSets(&test.left, &test.right, test.leftPC, test.rightPC) + if !reflect.DeepEqual(merged, test.merged) { + t.Errorf("mergeRuneSet :%d (%v, %v) merged\n have\n%v\nwant\n%v", ix, test.left, test.right, merged, test.merged) + } + if !reflect.DeepEqual(next, test.next) { + t.Errorf("mergeRuneSet :%d(%v, %v) next\n have\n%v\nwant\n%v", ix, test.left, test.right, next, test.next) + } + } +} + +const noStr = `!` + +var onePass = &onePassProg{} + +var onePassTests = []struct { + re string + onePass *onePassProg + prog string +}{ + {`^(?:a|(?:a*))$`, notOnePass, noStr}, + {`^(?:(a)|(?:a*))$`, notOnePass, noStr}, + {`^(?:(?:(?:.(?:$))?))$`, onePass, `a`}, + {`^abcd$`, onePass, `abcd`}, + {`^abcd$`, onePass, `abcde`}, + {`^(?:(?:a{0,})*?)$`, onePass, `a`}, + {`^(?:(?:a+)*)$`, onePass, ``}, + {`^(?:(?:a|(?:aa)))$`, onePass, ``}, + {`^(?:[^\s\S])$`, onePass, ``}, + {`^(?:(?:a{3,4}){0,})$`, notOnePass, `aaaaaa`}, + {`^(?:(?:a+)*)$`, onePass, `a`}, + {`^(?:(?:(?:a*)+))$`, onePass, noStr}, + {`^(?:(?:a+)*)$`, onePass, ``}, + {`^[a-c]+$`, onePass, `abc`}, + {`^[a-c]*$`, onePass, `abcdabc`}, + {`^(?:a*)$`, onePass, `aaaaaaa`}, + {`^(?:(?:aa)|a)$`, onePass, `a`}, + {`^[a-c]*`, notOnePass, `abcdabc`}, + {`^[a-c]*$`, onePass, `abc`}, + {`^...$`, onePass, ``}, + {`^(?:a|(?:aa))$`, onePass, `a`}, + {`^[a-c]*`, notOnePass, `abcabc`}, + {`^a((b))c$`, onePass, noStr}, + {`^a.[l-nA-Cg-j]?e$`, onePass, noStr}, + {`^a((b))$`, onePass, noStr}, + {`^a(?:(b)|(c))c$`, onePass, noStr}, + {`^a(?:(b*)|(c))c$`, notOnePass, noStr}, + {`^a(?:b|c)$`, onePass, noStr}, + {`^a(?:b?|c)$`, onePass, noStr}, + {`^a(?:b?|c?)$`, notOnePass, noStr}, + {`^a(?:b?|c+)$`, onePass, noStr}, + {`^a(?:b+|(bc))d$`, notOnePass, noStr}, + {`^a(?:bc)+$`, onePass, noStr}, + {`^a(?:[bcd])+$`, onePass, noStr}, + {`^a((?:[bcd])+)$`, onePass, noStr}, + {`^a(:?b|c)*d$`, onePass, `abbbccbbcbbd"`}, + {`^.bc(d|e)*$`, onePass, `abcddddddeeeededd`}, + {`^(?:(?:aa)|.)$`, notOnePass, `a`}, + {`^(?:(?:a{1,2}){1,2})$`, notOnePass, `aaaa`}, +} + +func TestCompileOnePass(t *testing.T) { + var ( + p *syntax.Prog + re *syntax.Regexp + err error + ) + for _, test := range onePassTests { + if re, err = syntax.Parse(test.re, syntax.Perl); err != nil { + t.Errorf("Parse(%q) got err:%s, want success", test.re, err) + continue + } + // needs to be done before compile... + re = re.Simplify() + if p, err = syntax.Compile(re); err != nil { + t.Errorf("Compile(%q) got err:%s, want success", test.re, err) + continue + } + onePass = compileOnePass(p) + if (onePass == notOnePass) != (test.onePass == notOnePass) { + t.Errorf("CompileOnePass(%q) got %v, expected %v", test.re, onePass, test.onePass) + } + } +} diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go index 6ce5902a5aa..0b8336a04fb 100644 --- a/libgo/go/regexp/regexp.go +++ b/libgo/go/regexp/regexp.go @@ -11,6 +11,14 @@ // For an overview of the syntax, run // godoc regexp/syntax // +// The regexp implementation provided by this package is +// guaranteed to run in time linear in the size of the input. +// (This is a property not guaranteed by most open source +// implementations of regular expressions.) For more information +// about this property, see +// http://swtch.com/~rsc/regexp/regexp1.html +// or any book about automata theory. +// // All characters are UTF-8-encoded code points. // // There are 16 methods of Regexp that match a regular expression and identify @@ -75,10 +83,12 @@ type Regexp struct { // read-only after Compile expr string // as passed to Compile prog *syntax.Prog // compiled program + onepass *onePassProg // onpass program or nil prefix string // required prefix in unanchored matches prefixBytes []byte // prefix, as a []byte prefixComplete bool // prefix is the entire regexp prefixRune rune // first rune in prefix + prefixEnd uint32 // pc for last rune in prefix cond syntax.EmptyOp // empty-width conditions required at start of match numSubexp int subexpNames []string @@ -155,12 +165,17 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) { regexp := &Regexp{ expr: expr, prog: prog, + onepass: compileOnePass(prog), numSubexp: maxCap, subexpNames: capNames, cond: prog.StartCond(), longest: longest, } - regexp.prefix, regexp.prefixComplete = prog.Prefix() + if regexp.onepass == notOnePass { + regexp.prefix, regexp.prefixComplete = prog.Prefix() + } else { + regexp.prefix, regexp.prefixComplete, regexp.prefixEnd = onePassPrefix(prog) + } if regexp.prefix != "" { // TODO(rsc): Remove this allocation by adding // IndexString to package bytes. @@ -182,7 +197,7 @@ func (re *Regexp) get() *machine { return z } re.mu.Unlock() - z := progMachine(re.prog) + z := progMachine(re.prog, re.onepass) z.re = re return z } diff --git a/libgo/go/regexp/syntax/doc.go b/libgo/go/regexp/syntax/doc.go index e52632ef726..8e72c90d3eb 100644 --- a/libgo/go/regexp/syntax/doc.go +++ b/libgo/go/regexp/syntax/doc.go @@ -46,6 +46,10 @@ Repetitions: x{n,}? n or more x, prefer fewer x{n}? exactly n x +Implementation restriction: The counting forms x{n} etc. (but not the other +forms x* etc.) have an upper limit of n=1000. Negative or higher explicit +counts yield the parse error ErrInvalidRepeatSize. + Grouping: (re) numbered capturing group (submatch) (?P<name>re) named & numbered capturing group (submatch) diff --git a/libgo/go/regexp/syntax/parse.go b/libgo/go/regexp/syntax/parse.go index 42d0bf4a16f..cb25dca3956 100644 --- a/libgo/go/regexp/syntax/parse.go +++ b/libgo/go/regexp/syntax/parse.go @@ -668,7 +668,6 @@ func Parse(s string, flags Flags) (*Regexp, error) { c rune op Op lastRepeat string - min, max int ) p.flags = flags p.wholeRegexp = s @@ -740,7 +739,7 @@ func Parse(s string, flags Flags) (*Regexp, error) { op = OpQuest } after := t[1:] - if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil { + if after, err = p.repeat(op, 0, 0, before, after, lastRepeat); err != nil { return nil, err } repeat = before diff --git a/libgo/go/regexp/syntax/prog.go b/libgo/go/regexp/syntax/prog.go index a482a82f215..29bd282d0d9 100644 --- a/libgo/go/regexp/syntax/prog.go +++ b/libgo/go/regexp/syntax/prog.go @@ -37,6 +37,27 @@ const ( InstRuneAnyNotNL ) +var instOpNames = []string{ + "InstAlt", + "InstAltMatch", + "InstCapture", + "InstEmptyWidth", + "InstMatch", + "InstFail", + "InstNop", + "InstRune", + "InstRune1", + "InstRuneAny", + "InstRuneAnyNotNL", +} + +func (i InstOp) String() string { + if uint(i) >= uint(len(instOpNames)) { + return "" + } + return instOpNames[i] +} + // An EmptyOp specifies a kind or mixture of zero-width assertions. type EmptyOp uint8 @@ -103,13 +124,13 @@ func (p *Prog) String() string { // skipNop follows any no-op or capturing instructions // and returns the resulting pc. -func (p *Prog) skipNop(pc uint32) *Inst { +func (p *Prog) skipNop(pc uint32) (*Inst, uint32) { i := &p.Inst[pc] for i.Op == InstNop || i.Op == InstCapture { pc = i.Out i = &p.Inst[pc] } - return i + return i, pc } // op returns i.Op but merges all the Rune special cases into InstRune @@ -126,7 +147,7 @@ func (i *Inst) op() InstOp { // regexp must start with. Complete is true if the prefix // is the entire match. func (p *Prog) Prefix() (prefix string, complete bool) { - i := p.skipNop(uint32(p.Start)) + i, _ := p.skipNop(uint32(p.Start)) // Avoid allocation of buffer if prefix is empty. if i.op() != InstRune || len(i.Rune) != 1 { @@ -137,7 +158,7 @@ func (p *Prog) Prefix() (prefix string, complete bool) { var buf bytes.Buffer for i.op() == InstRune && len(i.Rune) == 1 && Flags(i.Arg)&FoldCase == 0 { buf.WriteRune(i.Rune[0]) - i = p.skipNop(i.Out) + i, _ = p.skipNop(i.Out) } return buf.String(), i.Op == InstMatch } @@ -166,35 +187,46 @@ Loop: return flag } +const noMatch = -1 + // MatchRune returns true if the instruction matches (and consumes) r. // It should only be called when i.Op == InstRune. func (i *Inst) MatchRune(r rune) bool { + return i.MatchRunePos(r) != noMatch +} + +// MatchRunePos checks whether the instruction matches (and consumes) r. +// If so, MatchRunePos returns the index of the matching rune pair +// (or, when len(i.Rune) == 1, rune singleton). +// If not, MatchRunePos returns -1. +// MatchRunePos should only be called when i.Op == InstRune. +func (i *Inst) MatchRunePos(r rune) int { rune := i.Rune // Special case: single-rune slice is from literal string, not char class. if len(rune) == 1 { r0 := rune[0] if r == r0 { - return true + return 0 } if Flags(i.Arg)&FoldCase != 0 { for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) { if r == r1 { - return true + return 0 } } } - return false + return noMatch } // Peek at the first few pairs. // Should handle ASCII well. for j := 0; j < len(rune) && j <= 8; j += 2 { if r < rune[j] { - return false + return noMatch } if r <= rune[j+1] { - return true + return j / 2 } } @@ -205,14 +237,14 @@ func (i *Inst) MatchRune(r rune) bool { m := lo + (hi-lo)/2 if c := rune[2*m]; c <= r { if r <= rune[2*m+1] { - return true + return m } lo = m + 1 } else { hi = m } } - return false + return noMatch } // As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char. diff --git a/libgo/go/regexp/syntax/prog_test.go b/libgo/go/regexp/syntax/prog_test.go index cd71abc2a47..50bfa3d4bef 100644 --- a/libgo/go/regexp/syntax/prog_test.go +++ b/libgo/go/regexp/syntax/prog_test.go @@ -4,9 +4,7 @@ package syntax -import ( - "testing" -) +import "testing" var compileTests = []struct { Regexp string diff --git a/libgo/go/runtime/chan_test.go b/libgo/go/runtime/chan_test.go index 782176c8836..ce4b3962717 100644 --- a/libgo/go/runtime/chan_test.go +++ b/libgo/go/runtime/chan_test.go @@ -431,27 +431,15 @@ func TestMultiConsumer(t *testing.T) { } func BenchmarkChanNonblocking(b *testing.B) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) myc := make(chan int) - for p := 0; p < procs; p++ { - go func() { - for atomic.AddInt32(&N, -1) >= 0 { - for g := 0; g < CallsPerSched; g++ { - select { - case <-myc: - default: - } - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + select { + case <-myc: + default: } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + } + }) } func BenchmarkSelectUncontended(b *testing.B) { @@ -713,23 +701,11 @@ func BenchmarkChanCreation(b *testing.B) { func BenchmarkChanSem(b *testing.B) { type Empty struct{} - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(0) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - myc := make(chan Empty, procs) - for p := 0; p < procs; p++ { - go func() { - for atomic.AddInt32(&N, -1) >= 0 { - for g := 0; g < CallsPerSched; g++ { - myc <- Empty{} - <-myc - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + myc := make(chan Empty, runtime.GOMAXPROCS(0)) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + myc <- Empty{} + <-myc + } + }) } diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go index d8bfdbdad6d..39e04345a10 100644 --- a/libgo/go/runtime/crash_test.go +++ b/libgo/go/runtime/crash_test.go @@ -9,6 +9,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" "testing" "text/template" @@ -32,6 +33,10 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd { func executeTest(t *testing.T, templ string, data interface{}) string { t.Skip("gccgo does not have a go command") + if runtime.GOOS == "nacl" { + t.Skip("skipping on nacl") + } + checkStaleRuntime(t) st := template.Must(template.New("crashSource").Parse(templ)) @@ -112,8 +117,9 @@ func TestLockedDeadlock2(t *testing.T) { func TestGoexitDeadlock(t *testing.T) { output := executeTest(t, goexitDeadlockSource, nil) - if output != "" { - t.Fatalf("expected no output, got:\n%s", output) + want := "no goroutines (main called runtime.Goexit) - deadlock!" + if !strings.Contains(output, want) { + t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want) } } @@ -133,6 +139,34 @@ func TestThreadExhaustion(t *testing.T) { } } +func TestRecursivePanic(t *testing.T) { + output := executeTest(t, recursivePanicSource, nil) + want := `wrap: bad +panic: again + +` + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } + +} + +func TestGoexitCrash(t *testing.T) { + output := executeTest(t, goexitExitSource, nil) + want := "no goroutines (main called runtime.Goexit) - deadlock!" + if !strings.Contains(output, want) { + t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want) + } +} + +func TestGoNil(t *testing.T) { + output := executeTest(t, goNilSource, nil) + want := "go of nil func value" + if !strings.Contains(output, want) { + t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want) + } +} + const crashSource = ` package main @@ -273,3 +307,61 @@ func main() { } } ` + +const recursivePanicSource = ` +package main + +import ( + "fmt" +) + +func main() { + func() { + defer func() { + fmt.Println(recover()) + }() + var x [8192]byte + func(x [8192]byte) { + defer func() { + if err := recover(); err != nil { + panic("wrap: " + err.(string)) + } + }() + panic("bad") + }(x) + }() + panic("again") +} +` + +const goexitExitSource = ` +package main + +import ( + "runtime" + "time" +) + +func main() { + go func() { + time.Sleep(time.Millisecond) + }() + i := 0 + runtime.SetFinalizer(&i, func(p *int) {}) + runtime.GC() + runtime.Goexit() +} +` + +const goNilSource = ` +package main + +func main() { + defer func() { + recover() + }() + var f func() + go f() + select{} +} +` diff --git a/libgo/go/runtime/debug/garbage.go b/libgo/go/runtime/debug/garbage.go index a724fdf8f60..edb3643871e 100644 --- a/libgo/go/runtime/debug/garbage.go +++ b/libgo/go/runtime/debug/garbage.go @@ -135,3 +135,19 @@ func SetMaxStack(bytes int) int { func SetMaxThreads(threads int) int { return setMaxThreads(threads) } + +// SetPanicOnFault controls the runtime's behavior when a program faults +// at an unexpected (non-nil) address. Such faults are typically caused by +// bugs such as runtime memory corruption, so the default response is to crash +// the program. Programs working with memory-mapped files or unsafe +// manipulation of memory may cause faults at non-nil addresses in less +// dramatic situations; SetPanicOnFault allows such programs to request +// that the runtime trigger only a panic, not a crash. +// SetPanicOnFault applies only to the current goroutine. +// It returns the previous setting. +func SetPanicOnFault(enabled bool) bool + +// WriteHeapDump writes a description of the heap and the objects in +// it to the given file descriptor. +// The heap dump format is defined at http://golang.org/s/go13heapdump. +func WriteHeapDump(fd uintptr) diff --git a/libgo/go/runtime/debug/heapdump_test.go b/libgo/go/runtime/debug/heapdump_test.go new file mode 100644 index 00000000000..9201901151f --- /dev/null +++ b/libgo/go/runtime/debug/heapdump_test.go @@ -0,0 +1,33 @@ +// Copyright 2014 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. + +package debug + +import ( + "io/ioutil" + "os" + "runtime" + "testing" +) + +func TestWriteHeapDumpNonempty(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("WriteHeapDump is not available on NaCl.") + } + f, err := ioutil.TempFile("", "heapdumptest") + if err != nil { + t.Fatalf("TempFile failed: %v", err) + } + defer os.Remove(f.Name()) + defer f.Close() + WriteHeapDump(f.Fd()) + fi, err := f.Stat() + if err != nil { + t.Fatalf("Stat failed: %v", err) + } + const minSize = 1 + if size := fi.Size(); size < minSize { + t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize) + } +} diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go index 85b69cfdcfc..333d4fd000f 100644 --- a/libgo/go/runtime/extern.go +++ b/libgo/go/runtime/extern.go @@ -36,6 +36,9 @@ a comma-separated list of name=val pairs. Supported names are: length of the pause. Setting gctrace=2 emits the same summary but also repeats each collection. + gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots + that it thinks are dead. + scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit detailed multiline info every X milliseconds, describing state of the scheduler, processors, threads and goroutines. @@ -76,6 +79,11 @@ func Gosched() // Goexit terminates the goroutine that calls it. No other goroutine is affected. // Goexit runs all deferred calls before terminating the goroutine. +// +// Calling Goexit from the main goroutine terminates that goroutine +// without func main returning. Since func main has not returned, +// the program continues execution of other goroutines. +// If all other goroutines exit, the program crashes. func Goexit() // Caller reports file and line number information about function invocations on @@ -182,10 +190,8 @@ func GOROOT() string { } // Version returns the Go tree's version string. -// It is either a sequence number or, when possible, -// a release tag like "release.2010-03-04". -// A trailing + indicates that the tree had local modifications -// at the time of the build. +// It is either the commit hash and date at the time of the build or, +// when possible, a release tag like "go1.3". func Version() string { return theVersion } diff --git a/libgo/go/runtime/gc_test.go b/libgo/go/runtime/gc_test.go index 1b3ccbf7d93..5a1e9b89c42 100644 --- a/libgo/go/runtime/gc_test.go +++ b/libgo/go/runtime/gc_test.go @@ -9,6 +9,7 @@ import ( "runtime" "runtime/debug" "testing" + "time" ) func TestGcSys(t *testing.T) { @@ -153,3 +154,85 @@ func TestGcRescan(t *testing.T) { } } } + +func TestGcLastTime(t *testing.T) { + ms := new(runtime.MemStats) + t0 := time.Now().UnixNano() + runtime.GC() + t1 := time.Now().UnixNano() + runtime.ReadMemStats(ms) + last := int64(ms.LastGC) + if t0 > last || last > t1 { + t.Fatalf("bad last GC time: got %v, want [%v, %v]", last, t0, t1) + } +} + +func BenchmarkSetTypeNoPtr1(b *testing.B) { + type NoPtr1 struct { + p uintptr + } + var p *NoPtr1 + for i := 0; i < b.N; i++ { + p = &NoPtr1{} + } + _ = p +} +func BenchmarkSetTypeNoPtr2(b *testing.B) { + type NoPtr2 struct { + p, q uintptr + } + var p *NoPtr2 + for i := 0; i < b.N; i++ { + p = &NoPtr2{} + } + _ = p +} +func BenchmarkSetTypePtr1(b *testing.B) { + type Ptr1 struct { + p *byte + } + var p *Ptr1 + for i := 0; i < b.N; i++ { + p = &Ptr1{} + } + _ = p +} +func BenchmarkSetTypePtr2(b *testing.B) { + type Ptr2 struct { + p, q *byte + } + var p *Ptr2 + for i := 0; i < b.N; i++ { + p = &Ptr2{} + } + _ = p +} + +func BenchmarkAllocation(b *testing.B) { + type T struct { + x, y *byte + } + ngo := runtime.GOMAXPROCS(0) + work := make(chan bool, b.N+ngo) + result := make(chan *T) + for i := 0; i < b.N; i++ { + work <- true + } + for i := 0; i < ngo; i++ { + work <- false + } + for i := 0; i < ngo; i++ { + go func() { + var x *T + for <-work { + for i := 0; i < 1000; i++ { + x = &T{} + } + } + result <- x + }() + } + for i := 0; i < ngo; i++ { + <-result + } +} diff --git a/libgo/go/runtime/map_test.go b/libgo/go/runtime/map_test.go index fe5d3ad86c9..d9690253582 100644 --- a/libgo/go/runtime/map_test.go +++ b/libgo/go/runtime/map_test.go @@ -449,3 +449,43 @@ func TestMapIterOrder(t *testing.T) { } } } + +func TestMapStringBytesLookup(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("skipping for gccgo") + } + // Use large string keys to avoid small-allocation coalescing, + // which can cause AllocsPerRun to report lower counts than it should. + m := map[string]int{ + "1000000000000000000000000000000000000000000000000": 1, + "2000000000000000000000000000000000000000000000000": 2, + } + buf := []byte("1000000000000000000000000000000000000000000000000") + if x := m[string(buf)]; x != 1 { + t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x) + } + buf[0] = '2' + if x := m[string(buf)]; x != 2 { + t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x) + } + + var x int + n := testing.AllocsPerRun(100, func() { + x += m[string(buf)] + }) + if n != 0 { + t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n) + } + + x = 0 + n = testing.AllocsPerRun(100, func() { + y, ok := m[string(buf)] + if !ok { + panic("!ok") + } + x += y + }) + if n != 0 { + t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n) + } +} diff --git a/libgo/go/runtime/memmove_test.go b/libgo/go/runtime/memmove_test.go index 5c01aac97a9..540f0feb549 100644 --- a/libgo/go/runtime/memmove_test.go +++ b/libgo/go/runtime/memmove_test.go @@ -161,3 +161,83 @@ func BenchmarkMemclr64(b *testing.B) { bmMemclr(b, 64) } func BenchmarkMemclr256(b *testing.B) { bmMemclr(b, 256) } func BenchmarkMemclr4096(b *testing.B) { bmMemclr(b, 4096) } func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) } + +func BenchmarkClearFat32(b *testing.B) { + for i := 0; i < b.N; i++ { + var x [32]byte + _ = x + } +} +func BenchmarkClearFat64(b *testing.B) { + for i := 0; i < b.N; i++ { + var x [64]byte + _ = x + } +} +func BenchmarkClearFat128(b *testing.B) { + for i := 0; i < b.N; i++ { + var x [128]byte + _ = x + } +} +func BenchmarkClearFat256(b *testing.B) { + for i := 0; i < b.N; i++ { + var x [256]byte + _ = x + } +} +func BenchmarkClearFat512(b *testing.B) { + for i := 0; i < b.N; i++ { + var x [512]byte + _ = x + } +} +func BenchmarkClearFat1024(b *testing.B) { + for i := 0; i < b.N; i++ { + var x [1024]byte + _ = x + } +} + +func BenchmarkCopyFat32(b *testing.B) { + var x [32 / 4]uint32 + for i := 0; i < b.N; i++ { + y := x + _ = y + } +} +func BenchmarkCopyFat64(b *testing.B) { + var x [64 / 4]uint32 + for i := 0; i < b.N; i++ { + y := x + _ = y + } +} +func BenchmarkCopyFat128(b *testing.B) { + var x [128 / 4]uint32 + for i := 0; i < b.N; i++ { + y := x + _ = y + } +} +func BenchmarkCopyFat256(b *testing.B) { + var x [256 / 4]uint32 + for i := 0; i < b.N; i++ { + y := x + _ = y + } +} +func BenchmarkCopyFat512(b *testing.B) { + var x [512 / 4]uint32 + for i := 0; i < b.N; i++ { + y := x + _ = y + } +} +func BenchmarkCopyFat1024(b *testing.B) { + var x [1024 / 4]uint32 + for i := 0; i < b.N; i++ { + y := x + _ = y + } +} diff --git a/libgo/go/runtime/mfinal_test.go b/libgo/go/runtime/mfinal_test.go index ffcffbd4bef..b47f83c3923 100644 --- a/libgo/go/runtime/mfinal_test.go +++ b/libgo/go/runtime/mfinal_test.go @@ -6,10 +6,9 @@ package runtime_test import ( "runtime" - "sync" - "sync/atomic" "testing" "time" + "unsafe" ) type Tintptr *int // assignable to *int @@ -112,50 +111,133 @@ func TestFinalizerZeroSizedStruct(t *testing.T) { } func BenchmarkFinalizer(b *testing.B) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - var wg sync.WaitGroup - wg.Add(procs) - for p := 0; p < procs; p++ { - go func() { - var data [CallsPerSched]*int - for i := 0; i < CallsPerSched; i++ { - data[i] = new(int) + const Batch = 1000 + b.RunParallel(func(pb *testing.PB) { + var data [Batch]*int + for i := 0; i < Batch; i++ { + data[i] = new(int) + } + for pb.Next() { + for i := 0; i < Batch; i++ { + runtime.SetFinalizer(data[i], fin) } - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for i := 0; i < CallsPerSched; i++ { - runtime.SetFinalizer(data[i], fin) - } - for i := 0; i < CallsPerSched; i++ { - runtime.SetFinalizer(data[i], nil) - } + for i := 0; i < Batch; i++ { + runtime.SetFinalizer(data[i], nil) } - wg.Done() - }() - } - wg.Wait() + } + }) } func BenchmarkFinalizerRun(b *testing.B) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - var wg sync.WaitGroup - wg.Add(procs) - for p := 0; p < procs; p++ { - go func() { - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for i := 0; i < CallsPerSched; i++ { - v := new(int) - runtime.SetFinalizer(v, fin) - } - runtime.GC() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + v := new(int) + runtime.SetFinalizer(v, fin) + } + }) +} + +// One chunk must be exactly one sizeclass in size. +// It should be a sizeclass not used much by others, so we +// have a greater chance of finding adjacent ones. +// size class 19: 320 byte objects, 25 per page, 1 page alloc at a time +const objsize = 320 + +type objtype [objsize]byte + +func adjChunks() (*objtype, *objtype) { + var s []*objtype + + for { + c := new(objtype) + for _, d := range s { + if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) { + return c, d } - wg.Done() - }() + if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) { + return d, c + } + } + s = append(s, c) + } +} + +// Make sure an empty slice on the stack doesn't pin the next object in memory. +func TestEmptySlice(t *testing.T) { + if true { // disable until bug 7564 is fixed. + return + } + x, y := adjChunks() + + // the pointer inside xs points to y. + xs := x[objsize:] // change objsize to objsize-1 and the test passes + + fin := make(chan bool, 1) + runtime.SetFinalizer(y, func(z *objtype) { fin <- true }) + runtime.GC() + select { + case <-fin: + case <-time.After(4 * time.Second): + t.Errorf("finalizer of next object in memory didn't run") + } + xsglobal = xs // keep empty slice alive until here +} + +var xsglobal []byte + +func adjStringChunk() (string, *objtype) { + b := make([]byte, objsize) + for { + s := string(b) + t := new(objtype) + p := *(*uintptr)(unsafe.Pointer(&s)) + q := uintptr(unsafe.Pointer(t)) + if p+objsize == q { + return s, t + } + } +} + +// Make sure an empty string on the stack doesn't pin the next object in memory. +func TestEmptyString(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("skipping for gccgo") + } + + x, y := adjStringChunk() + + ss := x[objsize:] // change objsize to objsize-1 and the test passes + fin := make(chan bool, 1) + // set finalizer on string contents of y + runtime.SetFinalizer(y, func(z *objtype) { fin <- true }) + runtime.GC() + select { + case <-fin: + case <-time.After(4 * time.Second): + t.Errorf("finalizer of next string in memory didn't run") } - wg.Wait() + ssglobal = ss // keep 0-length string live until here +} + +var ssglobal string + +// Test for issue 7656. +func TestFinalizerOnGlobal(t *testing.T) { + runtime.SetFinalizer(Foo1, func(p *Object1) {}) + runtime.SetFinalizer(Foo2, func(p *Object2) {}) + runtime.SetFinalizer(Foo1, nil) + runtime.SetFinalizer(Foo2, nil) } + +type Object1 struct { + Something []byte +} + +type Object2 struct { + Something byte +} + +var ( + Foo2 = &Object2{} + Foo1 = &Object1{} +) diff --git a/libgo/go/runtime/mgc0.go b/libgo/go/runtime/mgc0.go index b1505466222..624485d18bf 100644 --- a/libgo/go/runtime/mgc0.go +++ b/libgo/go/runtime/mgc0.go @@ -9,7 +9,19 @@ func gc_m_ptr(ret *interface{}) { *ret = (*m)(nil) } +// Called from C. Returns the Go type *g. +func gc_g_ptr(ret *interface{}) { + *ret = (*g)(nil) +} + // Called from C. Returns the Go type *itab. func gc_itab_ptr(ret *interface{}) { *ret = (*itab)(nil) } + +func timenow() (sec int64, nsec int32) + +func gc_unixnanotime(now *int64) { + sec, nsec := timenow() + *now = sec*1e9 + int64(nsec) +} diff --git a/libgo/go/runtime/norace_test.go b/libgo/go/runtime/norace_test.go index a3d5b00860c..3b171877a6f 100644 --- a/libgo/go/runtime/norace_test.go +++ b/libgo/go/runtime/norace_test.go @@ -9,7 +9,6 @@ package runtime_test import ( "runtime" - "sync/atomic" "testing" ) @@ -31,28 +30,17 @@ func BenchmarkSyscallExcessWork(b *testing.B) { } func benchmarkSyscall(b *testing.B, work, excess int) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) * excess - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - foo := 42 - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - runtime.Entersyscall() - for i := 0; i < work; i++ { - foo *= 2 - foo /= 2 - } - runtime.Exitsyscall() - } + b.SetParallelism(excess) + b.RunParallel(func(pb *testing.PB) { + foo := 42 + for pb.Next() { + runtime.Entersyscall() + for i := 0; i < work; i++ { + foo *= 2 + foo /= 2 } - c <- foo == 42 - }() - } - for p := 0; p < procs; p++ { - <-c - } + runtime.Exitsyscall() + } + _ = foo + }) } diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go index 98080457cb5..26aa0b8be5c 100644 --- a/libgo/go/runtime/pprof/pprof.go +++ b/libgo/go/runtime/pprof/pprof.go @@ -20,7 +20,7 @@ import ( "text/tabwriter" ) -// BUG(rsc): Profiles are incomplete and inaccuate on NetBSD and OS X. +// BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X. // See http://golang.org/issue/6047 for details. // A Profile is a collection of stack traces showing the call sequences diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go index cce60e1be3b..f714472fd55 100644 --- a/libgo/go/runtime/pprof/pprof_test.go +++ b/libgo/go/runtime/pprof/pprof_test.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !nacl + package pprof_test import ( diff --git a/libgo/go/runtime/proc_test.go b/libgo/go/runtime/proc_test.go index bdcb199d727..4f364dc4636 100644 --- a/libgo/go/runtime/proc_test.go +++ b/libgo/go/runtime/proc_test.go @@ -373,24 +373,11 @@ func TestSchedLocalQueueSteal(t *testing.T) { } func benchmarkStackGrowth(b *testing.B, rec int) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - stackGrowthRecursive(rec) - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + stackGrowthRecursive(rec) + } + }) } func BenchmarkStackGrowth(b *testing.B) { diff --git a/libgo/go/runtime/runtime_test.go b/libgo/go/runtime/runtime_test.go index 1702298aed1..7dae95a2d4f 100644 --- a/libgo/go/runtime/runtime_test.go +++ b/libgo/go/runtime/runtime_test.go @@ -10,9 +10,11 @@ import ( // "os" // "os/exec" // . "runtime" + "runtime/debug" // "strconv" // "strings" "testing" + "unsafe" ) var errf error @@ -95,10 +97,10 @@ func BenchmarkDeferMany(b *testing.B) { // The value reported will include the padding between runtime.gogo and the // next function in memory. That's fine. func TestRuntimeGogoBytes(t *testing.T) { - // TODO(brainman): delete when issue 6973 is fixed. - if GOOS == "windows" { - t.Skip("skipping broken test on windows") + if GOOS == "nacl" { + t.Skip("skipping on nacl") } + dir, err := ioutil.TempDir("", "go-build") if err != nil { t.Fatalf("failed to create temp directory: %v", err) @@ -134,3 +136,77 @@ func TestRuntimeGogoBytes(t *testing.T) { func TestStopCPUProfilingWithProfilerOff(t *testing.T) { SetCPUProfileRate(0) } + +// Addresses to test for faulting behavior. +// This is less a test of SetPanicOnFault and more a check that +// the operating system and the runtime can process these faults +// correctly. That is, we're indirectly testing that without SetPanicOnFault +// these would manage to turn into ordinary crashes. +// Note that these are truncated on 32-bit systems, so the bottom 32 bits +// of the larger addresses must themselves be invalid addresses. +// We might get unlucky and the OS might have mapped one of these +// addresses, but probably not: they're all in the first page, very high +// adderesses that normally an OS would reserve for itself, or malformed +// addresses. Even so, we might have to remove one or two on different +// systems. We will see. + +var faultAddrs = []uint64{ + // low addresses + 0, + 1, + 0xfff, + // high (kernel) addresses + // or else malformed. + 0xffffffffffffffff, + 0xfffffffffffff001, + // no 0xffffffffffff0001; 0xffff0001 is mapped for 32-bit user space on OS X + // no 0xfffffffffff00001; 0xfff00001 is mapped for 32-bit user space sometimes on Linux + 0xffffffffff000001, + 0xfffffffff0000001, + 0xffffffff00000001, + 0xfffffff000000001, + 0xffffff0000000001, + 0xfffff00000000001, + 0xffff000000000001, + 0xfff0000000000001, + 0xff00000000000001, + 0xf000000000000001, + 0x8000000000000001, +} + +func TestSetPanicOnFault(t *testing.T) { + // This currently results in a fault in the signal trampoline on + // dragonfly/386 - see issue 7421. + if GOOS == "dragonfly" && GOARCH == "386" { + t.Skip("skipping test on dragonfly/386") + } + + old := debug.SetPanicOnFault(true) + defer debug.SetPanicOnFault(old) + + for _, addr := range faultAddrs { + if Compiler == "gccgo" && GOARCH == "386" && (addr&0xff000000) != 0 { + // On gccgo these addresses can be used for + // the thread stack. + continue + } + testSetPanicOnFault(t, uintptr(addr)) + } +} + +func testSetPanicOnFault(t *testing.T, addr uintptr) { + if GOOS == "nacl" { + t.Skip("nacl doesn't seem to fault on high addresses") + } + + defer func() { + if err := recover(); err == nil { + t.Fatalf("did not find error in recover") + } + }() + + var p *int + p = (*int)(unsafe.Pointer(addr)) + println(*p) + t.Fatalf("still here - should have faulted on address %#x", addr) +} diff --git a/libgo/go/runtime/type.go b/libgo/go/runtime/type.go index eba34e4a6ba..1211f222575 100644 --- a/libgo/go/runtime/type.go +++ b/libgo/go/runtime/type.go @@ -27,6 +27,7 @@ type rtype struct { string *string *uncommonType ptrToThis *rtype + zero unsafe.Pointer } type _method struct { diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go index 242c5fffa21..e980c295c32 100644 --- a/libgo/go/sort/sort.go +++ b/libgo/go/sort/sort.go @@ -287,7 +287,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) } // Notes on stable sorting: // The used algorithms are simple and provable correct on all input and use // only logarithmic additional stack space. They perform well if compared -// experimentaly to other stable in-place sorting algorithms. +// experimentally to other stable in-place sorting algorithms. // // Remarks on other algorithms evaluated: // - GCC's 4.6.3 stable_sort with merge_without_buffer from libstdc++: diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go index 2d0db7155f7..cbf0380ec82 100644 --- a/libgo/go/strconv/atoi.go +++ b/libgo/go/strconv/atoi.go @@ -142,9 +142,11 @@ Error: // // The errors that ParseInt returns have concrete type *NumError // and include err.Num = s. If s is empty or contains invalid -// digits, err.Err = ErrSyntax; if the value corresponding -// to s cannot be represented by a signed integer of the -// given size, err.Err = ErrRange. +// digits, err.Err = ErrSyntax and the returned value is 0; +// if the value corresponding to s cannot be represented by a +// signed integer of the given size, err.Err = ErrRange and the +// returned value is the maximum magnitude integer of the +// appropriate bitSize and sign. func ParseInt(s string, base int, bitSize int) (i int64, err error) { const fnParseInt = "ParseInt" diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go index 7d6cdcf0b54..aded7e5930c 100644 --- a/libgo/go/strconv/quote.go +++ b/libgo/go/strconv/quote.go @@ -144,7 +144,8 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte { // characters other than space and tab. func CanBackquote(s string) bool { for i := 0; i < len(s); i++ { - if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' { + c := s[i] + if (c < ' ' && c != '\t') || c == '`' || c == '\u007F' { return false } } diff --git a/libgo/go/strconv/quote_test.go b/libgo/go/strconv/quote_test.go index 61d9bf9a571..e4b5b6b9fd2 100644 --- a/libgo/go/strconv/quote_test.go +++ b/libgo/go/strconv/quote_test.go @@ -140,6 +140,7 @@ var canbackquotetests = []canBackquoteTest{ {string(29), false}, {string(30), false}, {string(31), false}, + {string(0x7F), false}, {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true}, {`0123456789`, true}, {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true}, diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go index 11240efc078..82df974398c 100644 --- a/libgo/go/strings/reader.go +++ b/libgo/go/strings/reader.go @@ -15,40 +15,41 @@ import ( // from a string. type Reader struct { s string - i int // current reading index - prevRune int // index of previous rune; or < 0 + i int64 // current reading index + prevRune int // index of previous rune; or < 0 } // Len returns the number of bytes of the unread portion of the // string. func (r *Reader) Len() int { - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { return 0 } - return len(r.s) - r.i + return int(int64(len(r.s)) - r.i) } func (r *Reader) Read(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil } - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { return 0, io.EOF } - n = copy(b, r.s[r.i:]) - r.i += n r.prevRune = -1 + n = copy(b, r.s[r.i:]) + r.i += int64(n) return } func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { + // cannot modify state - see io.ReaderAt if off < 0 { - return 0, errors.New("strings: invalid offset") + return 0, errors.New("strings.Reader.ReadAt: negative offset") } if off >= int64(len(r.s)) { return 0, io.EOF } - n = copy(b, r.s[int(off):]) + n = copy(b, r.s[off:]) if n < len(b) { err = io.EOF } @@ -56,49 +57,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) { } func (r *Reader) ReadByte() (b byte, err error) { - if r.i >= len(r.s) { + r.prevRune = -1 + if r.i >= int64(len(r.s)) { return 0, io.EOF } b = r.s[r.i] r.i++ - r.prevRune = -1 return } func (r *Reader) UnreadByte() error { + r.prevRune = -1 if r.i <= 0 { - return errors.New("strings.Reader: at beginning of string") + return errors.New("strings.Reader.UnreadByte: at beginning of string") } r.i-- - r.prevRune = -1 return nil } func (r *Reader) ReadRune() (ch rune, size int, err error) { - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { + r.prevRune = -1 return 0, 0, io.EOF } - r.prevRune = r.i + r.prevRune = int(r.i) if c := r.s[r.i]; c < utf8.RuneSelf { r.i++ return rune(c), 1, nil } ch, size = utf8.DecodeRuneInString(r.s[r.i:]) - r.i += size + r.i += int64(size) return } func (r *Reader) UnreadRune() error { if r.prevRune < 0 { - return errors.New("strings.Reader: previous operation was not ReadRune") + return errors.New("strings.Reader.UnreadRune: previous operation was not ReadRune") } - r.i = r.prevRune + r.i = int64(r.prevRune) r.prevRune = -1 return nil } // Seek implements the io.Seeker interface. func (r *Reader) Seek(offset int64, whence int) (int64, error) { + r.prevRune = -1 var abs int64 switch whence { case 0: @@ -108,22 +111,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) { case 2: abs = int64(len(r.s)) + offset default: - return 0, errors.New("strings: invalid whence") + return 0, errors.New("strings.Reader.Seek: invalid whence") } if abs < 0 { - return 0, errors.New("strings: negative position") - } - if abs >= 1<<31 { - return 0, errors.New("strings: position out of range") + return 0, errors.New("strings.Reader.Seek: negative position") } - r.i = int(abs) + r.i = abs return abs, nil } // WriteTo implements the io.WriterTo interface. func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { r.prevRune = -1 - if r.i >= len(r.s) { + if r.i >= int64(len(r.s)) { return 0, nil } s := r.s[r.i:] @@ -131,7 +131,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { if m > len(s) { panic("strings.Reader.WriteTo: invalid WriteString count") } - r.i += m + r.i += int64(m) n = int64(m) if m != len(s) && err == nil { err = io.ErrShortWrite diff --git a/libgo/go/strings/reader_test.go b/libgo/go/strings/reader_test.go index 4fdddcdb58e..bee90eb2585 100644 --- a/libgo/go/strings/reader_test.go +++ b/libgo/go/strings/reader_test.go @@ -10,6 +10,7 @@ import ( "io" "os" "strings" + "sync" "testing" ) @@ -26,9 +27,9 @@ func TestReader(t *testing.T) { {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"}, {seek: os.SEEK_SET, off: 1, n: 1, want: "1"}, {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"}, - {seek: os.SEEK_SET, off: -1, seekerr: "strings: negative position"}, - {seek: os.SEEK_SET, off: 1<<31 - 1}, - {seek: os.SEEK_CUR, off: 1, seekerr: "strings: position out of range"}, + {seek: os.SEEK_SET, off: -1, seekerr: "strings.Reader.Seek: negative position"}, + {seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33}, + {seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1}, {seek: os.SEEK_SET, n: 5, want: "01234"}, {seek: os.SEEK_CUR, n: 5, want: "56789"}, {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"}, @@ -60,6 +61,16 @@ func TestReader(t *testing.T) { } } +func TestReadAfterBigSeek(t *testing.T) { + r := strings.NewReader("0123456789") + if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil { + t.Fatal(err) + } + if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF { + t.Errorf("Read = %d, %v; want 0, EOF", n, err) + } +} + func TestReaderAt(t *testing.T) { r := strings.NewReader("0123456789") tests := []struct { @@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) { {1, 9, "123456789", nil}, {11, 10, "", io.EOF}, {0, 0, "", nil}, - {-1, 0, "", "strings: invalid offset"}, + {-1, 0, "", "strings.Reader.ReadAt: negative offset"}, } for i, tt := range tests { b := make([]byte, tt.n) @@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) { } } +func TestReaderAtConcurrent(t *testing.T) { + // Test for the race detector, to verify ReadAt doesn't mutate + // any state. + r := strings.NewReader("0123456789") + var wg sync.WaitGroup + for i := 0; i < 5; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + var buf [1]byte + r.ReadAt(buf[:], int64(i)) + }(i) + } + wg.Wait() +} + +func TestEmptyReaderConcurrent(t *testing.T) { + // Test for the race detector, to verify a Read that doesn't yield any bytes + // is okay to use from multiple goroutines. This was our historic behavior. + // See golang.org/issue/7856 + r := strings.NewReader("") + var wg sync.WaitGroup + for i := 0; i < 5; i++ { + wg.Add(2) + go func() { + defer wg.Done() + var buf [1]byte + r.Read(buf[:]) + }() + go func() { + defer wg.Done() + r.Read(nil) + }() + } + wg.Wait() +} + func TestWriteTo(t *testing.T) { const str = "0123456789" for i := 0; i <= len(str); i++ { diff --git a/libgo/go/strings/replace.go b/libgo/go/strings/replace.go index 54c9323e048..3e05d2057be 100644 --- a/libgo/go/strings/replace.go +++ b/libgo/go/strings/replace.go @@ -492,7 +492,7 @@ func (r *byteStringReplacer) Replace(s string) string { for i := 0; i < len(s); i++ { b := s[i] if r.old[b>>5]&uint32(1<<(b&31)) != 0 { - n := copy(bi[:], r.new[b]) + n := copy(bi, r.new[b]) bi = bi[n:] } else { bi[0] = b diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go index a5be2f9bed5..e40a18015e2 100644 --- a/libgo/go/strings/strings_test.go +++ b/libgo/go/strings/strings_test.go @@ -652,7 +652,7 @@ func equal(m string, s1, s2 string, t *testing.T) bool { e1 := Split(s1, "") e2 := Split(s2, "") for i, c1 := range e1 { - if i > len(e2) { + if i >= len(e2) { break } r1, _ := utf8.DecodeRuneInString(c1) @@ -858,6 +858,32 @@ func TestReadRune(t *testing.T) { } } +var UnreadRuneErrorTests = []struct { + name string + f func(*Reader) +}{ + {"Read", func(r *Reader) { r.Read([]byte{0}) }}, + {"ReadByte", func(r *Reader) { r.ReadByte() }}, + {"UnreadRune", func(r *Reader) { r.UnreadRune() }}, + {"Seek", func(r *Reader) { r.Seek(0, 1) }}, + {"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }}, +} + +func TestUnreadRuneError(t *testing.T) { + for _, tt := range UnreadRuneErrorTests { + reader := NewReader("0123456789") + if _, _, err := reader.ReadRune(); err != nil { + // should not happen + t.Fatal(err) + } + tt.f(reader) + err := reader.UnreadRune() + if err == nil { + t.Errorf("Unreading after %s: expected error", tt.name) + } + } +} + var ReplaceTests = []struct { in string old, new string diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go index 06dd5f7ce89..d2af4f41871 100644 --- a/libgo/go/sync/atomic/atomic_test.go +++ b/libgo/go/sync/atomic/atomic_test.go @@ -813,7 +813,7 @@ func hammerSwapUintptr32(uaddr *uint32, count int) { new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 old := SwapUintptr(addr, new) if old>>16 != old<<16>>16 { - panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old)) + panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old)) } } } @@ -827,7 +827,7 @@ func hammerSwapPointer32(uaddr *uint32, count int) { new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 old := uintptr(SwapPointer(addr, unsafe.Pointer(new))) if old>>16 != old<<16>>16 { - panic(fmt.Sprintf("SwapPointer is not atomic: %v", old)) + panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old)) } } } @@ -1465,6 +1465,9 @@ func TestUnaligned64(t *testing.T) { } func TestNilDeref(t *testing.T) { + if p := runtime.GOOS + "/" + runtime.GOARCH; p == "freebsd/arm" || p == "netbsd/arm" { + t.Skipf("issue 7338: skipping test on %q", p) + } funcs := [...]func(){ func() { CompareAndSwapInt32(nil, 0, 0) }, func() { CompareAndSwapInt64(nil, 0, 0) }, diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go index bf78c6f609c..151b25c10fc 100644 --- a/libgo/go/sync/mutex_test.go +++ b/libgo/go/sync/mutex_test.go @@ -9,7 +9,6 @@ package sync_test import ( "runtime" . "sync" - "sync/atomic" "testing" ) @@ -90,63 +89,34 @@ func BenchmarkMutexUncontended(b *testing.B) { Mutex pad [128]uint8 } - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - var mu PaddedMutex - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - mu.Lock() - mu.Unlock() - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + b.RunParallel(func(pb *testing.PB) { + var mu PaddedMutex + for pb.Next() { + mu.Lock() + mu.Unlock() + } + }) } func benchmarkMutex(b *testing.B, slack, work bool) { - const ( - CallsPerSched = 1000 - LocalWork = 100 - GoroutineSlack = 10 - ) - procs := runtime.GOMAXPROCS(-1) + var mu Mutex if slack { - procs *= GoroutineSlack + b.SetParallelism(10) } - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - var mu Mutex - for p := 0; p < procs; p++ { - go func() { - foo := 0 - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - mu.Lock() - mu.Unlock() - if work { - for i := 0; i < LocalWork; i++ { - foo *= 2 - foo /= 2 - } - } + b.RunParallel(func(pb *testing.PB) { + foo := 0 + for pb.Next() { + mu.Lock() + mu.Unlock() + if work { + for i := 0; i < 100; i++ { + foo *= 2 + foo /= 2 } } - c <- foo == 42 - }() - } - for p := 0; p < procs; p++ { - <-c - } + } + _ = foo + }) } func BenchmarkMutex(b *testing.B) { diff --git a/libgo/go/sync/once_test.go b/libgo/go/sync/once_test.go index 183069a1a23..8afda82f3e1 100644 --- a/libgo/go/sync/once_test.go +++ b/libgo/go/sync/once_test.go @@ -5,9 +5,7 @@ package sync_test import ( - "runtime" . "sync" - "sync/atomic" "testing" ) @@ -62,24 +60,11 @@ func TestOncePanic(t *testing.T) { } func BenchmarkOnce(b *testing.B) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) var once Once f := func() {} - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - once.Do(f) - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + once.Do(f) + } + }) } diff --git a/libgo/go/sync/pool.go b/libgo/go/sync/pool.go index ca49d21a0d1..1f08707cd42 100644 --- a/libgo/go/sync/pool.go +++ b/libgo/go/sync/pool.go @@ -10,64 +10,51 @@ import ( "unsafe" ) -const ( - cacheLineSize = 128 - poolLocalSize = 2 * cacheLineSize - poolLocalCap = poolLocalSize/unsafe.Sizeof(*(*interface{})(nil)) - 1 -) - -// A Pool is a set of temporary objects that may be individually saved -// and retrieved. +// A Pool is a set of temporary objects that may be individually saved and +// retrieved. // -// Any item stored in the Pool may be removed automatically by the -// implementation at any time without notification. -// If the Pool holds the only reference when this happens, the item -// might be deallocated. +// Any item stored in the Pool may be removed automatically at any time without +// notification. If the Pool holds the only reference when this happens, the +// item might be deallocated. // // A Pool is safe for use by multiple goroutines simultaneously. // -// Pool's intended use is for free lists maintained in global variables, -// typically accessed by multiple goroutines simultaneously. Using a -// Pool instead of a custom free list allows the runtime to reclaim -// entries from the pool when it makes sense to do so. An -// appropriate use of sync.Pool is to create a pool of temporary buffers -// shared between independent clients of a global resource. On the -// other hand, if a free list is maintained as part of an object used -// only by a single client and freed when the client completes, -// implementing that free list as a Pool is not appropriate. +// Pool's purpose is to cache allocated but unused items for later reuse, +// relieving pressure on the garbage collector. That is, it makes it easy to +// build efficient, thread-safe free lists. However, it is not suitable for all +// free lists. +// +// An appropriate use of a Pool is to manage a group of temporary items +// silently shared among and potentially reused by concurrent independent +// clients of a package. Pool provides a way to amortize allocation overhead +// across many clients. +// +// An example of good use of a Pool is in the fmt package, which maintains a +// dynamically-sized store of temporary output buffers. The store scales under +// load (when many goroutines are actively printing) and shrinks when +// quiescent. +// +// On the other hand, a free list maintained as part of a short-lived object is +// not a suitable use for a Pool, since the overhead does not amortize well in +// that scenario. It is more efficient to have such objects implement their own +// free list. // -// This is an experimental type and might not be released. type Pool struct { - // The following fields are known to runtime. - next *Pool // for use by runtime - local *poolLocal // local fixed-size per-P pool, actually an array - localSize uintptr // size of the local array - globalOffset uintptr // offset of global - // The rest is not known to runtime. + local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal + localSize uintptr // size of the local array // New optionally specifies a function to generate // a value when Get would otherwise return nil. // It may not be changed concurrently with calls to Get. New func() interface{} - - pad [cacheLineSize]byte - // Read-mostly date above this point, mutable data follows. - mu Mutex - global []interface{} // global fallback pool } // Local per-P Pool appendix. type poolLocal struct { - tail int - unused int - buf [poolLocalCap]interface{} -} - -func init() { - var v poolLocal - if unsafe.Sizeof(v) != poolLocalSize { - panic("sync: incorrect pool size") - } + private interface{} // Can be used only by the respective P. + shared []interface{} // Can be used by any P. + Mutex // Protects shared. + pad [128]byte // Prevents false sharing. } // Put adds x to the pool. @@ -82,14 +69,17 @@ func (p *Pool) Put(x interface{}) { return } l := p.pin() - t := l.tail - if t < int(poolLocalCap) { - l.buf[t] = x - l.tail = t + 1 - runtime_procUnpin() + if l.private == nil { + l.private = x + x = nil + } + runtime_procUnpin() + if x == nil { return } - p.putSlow(l, x) + l.Lock() + l.shared = append(l.shared, x) + l.Unlock() } // Get selects an arbitrary item from the Pool, removes it from the @@ -108,72 +98,52 @@ func (p *Pool) Get() interface{} { return nil } l := p.pin() - t := l.tail - if t > 0 { - t -= 1 - x := l.buf[t] - l.tail = t - runtime_procUnpin() + x := l.private + l.private = nil + runtime_procUnpin() + if x != nil { return x } - return p.getSlow() -} - -func (p *Pool) putSlow(l *poolLocal, x interface{}) { - // Grab half of items from local pool and put to global pool. - // Can not lock the mutex while pinned. - const N = int(poolLocalCap/2 + 1) - var buf [N]interface{} - buf[0] = x - for i := 1; i < N; i++ { - l.tail-- - buf[i] = l.buf[l.tail] + l.Lock() + last := len(l.shared) - 1 + if last >= 0 { + x = l.shared[last] + l.shared = l.shared[:last] } - runtime_procUnpin() - - p.mu.Lock() - p.global = append(p.global, buf[:]...) - p.mu.Unlock() + l.Unlock() + if x != nil { + return x + } + return p.getSlow() } func (p *Pool) getSlow() (x interface{}) { - // Grab a batch of items from global pool and put to local pool. - // Can not lock the mutex while pinned. - runtime_procUnpin() - p.mu.Lock() + // See the comment in pin regarding ordering of the loads. + size := atomic.LoadUintptr(&p.localSize) // load-acquire + local := p.local // load-consume + // Try to steal one element from other procs. pid := runtime_procPin() - s := p.localSize - l := p.local - if uintptr(pid) < s { - l = indexLocal(l, pid) - // Get the item to return. - last := len(p.global) - 1 + runtime_procUnpin() + for i := 0; i < int(size); i++ { + l := indexLocal(local, (pid+i+1)%int(size)) + l.Lock() + last := len(l.shared) - 1 if last >= 0 { - x = p.global[last] - p.global = p.global[:last] - } - // Try to refill local pool, we may have been rescheduled to another P. - if last > 0 && l.tail == 0 { - n := int(poolLocalCap / 2) - gl := len(p.global) - if n > gl { - n = gl - } - copy(l.buf[:], p.global[gl-n:]) - p.global = p.global[:gl-n] - l.tail = n + x = l.shared[last] + l.shared = l.shared[:last] + l.Unlock() + break } + l.Unlock() } - runtime_procUnpin() - p.mu.Unlock() if x == nil && p.New != nil { x = p.New() } - return + return x } -// pin pins current goroutine to P, disables preemption and returns poolLocal pool for the P. +// pin pins the current goroutine to P, disables preemption and returns poolLocal pool for the P. // Caller must call runtime_procUnpin() when done with the pool. func (p *Pool) pin() *poolLocal { pid := runtime_procPin() @@ -191,32 +161,63 @@ func (p *Pool) pin() *poolLocal { func (p *Pool) pinSlow() *poolLocal { // Retry under the mutex. + // Can not lock the mutex while pinned. runtime_procUnpin() - p.mu.Lock() - defer p.mu.Unlock() + allPoolsMu.Lock() + defer allPoolsMu.Unlock() pid := runtime_procPin() + // poolCleanup won't be called while we are pinned. s := p.localSize l := p.local if uintptr(pid) < s { return indexLocal(l, pid) } if p.local == nil { - p.globalOffset = unsafe.Offsetof(p.global) - runtime_registerPool(p) + allPools = append(allPools, p) } // If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one. size := runtime.GOMAXPROCS(0) local := make([]poolLocal, size) - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.local)), unsafe.Pointer(&local[0])) // store-release - atomic.StoreUintptr(&p.localSize, uintptr(size)) // store-release + atomic.StorePointer((*unsafe.Pointer)(&p.local), unsafe.Pointer(&local[0])) // store-release + atomic.StoreUintptr(&p.localSize, uintptr(size)) // store-release return &local[pid] } -func indexLocal(l *poolLocal, i int) *poolLocal { - return (*poolLocal)(unsafe.Pointer(uintptr(unsafe.Pointer(l)) + unsafe.Sizeof(*l)*uintptr(i))) // uh... +func poolCleanup() { + // This function is called with the world stopped, at the beginning of a garbage collection. + // It must not allocate and probably should not call any runtime functions. + // Defensively zero out everything, 2 reasons: + // 1. To prevent false retention of whole Pools. + // 2. If GC happens while a goroutine works with l.shared in Put/Get, + // it will retain whole Pool. So next cycle memory consumption would be doubled. + for i, p := range allPools { + allPools[i] = nil + for i := 0; i < int(p.localSize); i++ { + l := indexLocal(p.local, i) + l.private = nil + for j := range l.shared { + l.shared[j] = nil + } + l.shared = nil + } + } + allPools = []*Pool{} +} + +var ( + allPoolsMu Mutex + allPools []*Pool +) + +func init() { + runtime_registerPoolCleanup(poolCleanup) +} + +func indexLocal(l unsafe.Pointer, i int) *poolLocal { + return &(*[1000000]poolLocal)(l)[i] } // Implemented in runtime. -func runtime_registerPool(*Pool) +func runtime_registerPoolCleanup(cleanup func()) func runtime_procPin() int func runtime_procUnpin() diff --git a/libgo/go/sync/pool_test.go b/libgo/go/sync/pool_test.go index 39ba7a913d3..c13477de904 100644 --- a/libgo/go/sync/pool_test.go +++ b/libgo/go/sync/pool_test.go @@ -25,12 +25,12 @@ func TestPool(t *testing.T) { } p.Put("a") p.Put("b") - if g := p.Get(); g != "b" { - t.Fatalf("got %#v; want b", g) - } if g := p.Get(); g != "a" { t.Fatalf("got %#v; want a", g) } + if g := p.Get(); g != "b" { + t.Fatalf("got %#v; want b", g) + } if g := p.Get(); g != nil { t.Fatalf("got %#v; want nil", g) } @@ -87,7 +87,7 @@ func TestPoolGC(t *testing.T) { } for i := 0; i < 5; i++ { runtime.GC() - time.Sleep(time.Millisecond) + time.Sleep(time.Duration(i*100+10) * time.Millisecond) // 1 pointer can remain on stack or elsewhere if atomic.LoadUint32(&fin) >= N-1 { return @@ -133,42 +133,24 @@ func TestPoolStress(t *testing.T) { func BenchmarkPool(b *testing.B) { var p Pool - var wg WaitGroup - n0 := uintptr(b.N) - n := n0 - for i := 0; i < runtime.GOMAXPROCS(0); i++ { - wg.Add(1) - go func() { - defer wg.Done() - for atomic.AddUintptr(&n, ^uintptr(0)) < n0 { - for b := 0; b < 100; b++ { - p.Put(1) - p.Get() - } - } - }() - } - wg.Wait() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + p.Put(1) + p.Get() + } + }) } func BenchmarkPoolOverlflow(b *testing.B) { var p Pool - var wg WaitGroup - n0 := uintptr(b.N) - n := n0 - for i := 0; i < runtime.GOMAXPROCS(0); i++ { - wg.Add(1) - go func() { - defer wg.Done() - for atomic.AddUintptr(&n, ^uintptr(0)) < n0 { - for b := 0; b < 100; b++ { - p.Put(1) - } - for b := 0; b < 100; b++ { - p.Get() - } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + for b := 0; b < 100; b++ { + p.Put(1) } - }() - } - wg.Wait() + for b := 0; b < 100; b++ { + p.Get() + } + } + }) } diff --git a/libgo/go/sync/runtime_sema_test.go b/libgo/go/sync/runtime_sema_test.go index 57a8dbee783..5b7dd3df3f0 100644 --- a/libgo/go/sync/runtime_sema_test.go +++ b/libgo/go/sync/runtime_sema_test.go @@ -7,7 +7,6 @@ package sync_test import ( "runtime" . "sync" - "sync/atomic" "testing" ) @@ -16,72 +15,44 @@ func BenchmarkSemaUncontended(b *testing.B) { sem uint32 pad [32]uint32 } - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - sem := new(PaddedSem) - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - Runtime_Semrelease(&sem.sem) - Runtime_Semacquire(&sem.sem) - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + b.RunParallel(func(pb *testing.PB) { + sem := new(PaddedSem) + for pb.Next() { + Runtime_Semrelease(&sem.sem) + Runtime_Semacquire(&sem.sem) + } + }) } func benchmarkSema(b *testing.B, block, work bool) { - const CallsPerSched = 1000 - const LocalWork = 100 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - c2 := make(chan bool, procs/2) sem := uint32(0) if block { - for p := 0; p < procs/2; p++ { - go func() { - Runtime_Semacquire(&sem) - c2 <- true - }() - } - } - for p := 0; p < procs; p++ { + done := make(chan bool) go func() { - foo := 0 - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - Runtime_Semrelease(&sem) - if work { - for i := 0; i < LocalWork; i++ { - foo *= 2 - foo /= 2 - } - } - Runtime_Semacquire(&sem) - } + for p := 0; p < runtime.GOMAXPROCS(0)/2; p++ { + Runtime_Semacquire(&sem) } - c <- foo == 42 - Runtime_Semrelease(&sem) + done <- true + }() + defer func() { + <-done }() } - if block { - for p := 0; p < procs/2; p++ { - <-c2 + b.RunParallel(func(pb *testing.PB) { + foo := 0 + for pb.Next() { + Runtime_Semrelease(&sem) + if work { + for i := 0; i < 100; i++ { + foo *= 2 + foo /= 2 + } + } + Runtime_Semacquire(&sem) } - } - for p := 0; p < procs; p++ { - <-c - } + _ = foo + Runtime_Semrelease(&sem) + }) } func BenchmarkSemaSyntNonblock(b *testing.B) { diff --git a/libgo/go/sync/rwmutex_test.go b/libgo/go/sync/rwmutex_test.go index 39d5d6540de..0436f97239c 100644 --- a/libgo/go/sync/rwmutex_test.go +++ b/libgo/go/sync/rwmutex_test.go @@ -160,64 +160,39 @@ func BenchmarkRWMutexUncontended(b *testing.B) { RWMutex pad [32]uint32 } - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - var rwm PaddedRWMutex - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - rwm.RLock() - rwm.RLock() - rwm.RUnlock() - rwm.RUnlock() - rwm.Lock() - rwm.Unlock() - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + b.RunParallel(func(pb *testing.PB) { + var rwm PaddedRWMutex + for pb.Next() { + rwm.RLock() + rwm.RLock() + rwm.RUnlock() + rwm.RUnlock() + rwm.Lock() + rwm.Unlock() + } + }) } func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) var rwm RWMutex - for p := 0; p < procs; p++ { - go func() { - foo := 0 - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - foo++ - if foo%writeRatio == 0 { - rwm.Lock() - rwm.Unlock() - } else { - rwm.RLock() - for i := 0; i != localWork; i += 1 { - foo *= 2 - foo /= 2 - } - rwm.RUnlock() - } + b.RunParallel(func(pb *testing.PB) { + foo := 0 + for pb.Next() { + foo++ + if foo%writeRatio == 0 { + rwm.Lock() + rwm.Unlock() + } else { + rwm.RLock() + for i := 0; i != localWork; i += 1 { + foo *= 2 + foo /= 2 } + rwm.RUnlock() } - c <- foo == 42 - }() - } - for p := 0; p < procs; p++ { - <-c - } + } + _ = foo + }) } func BenchmarkRWMutexWrite100(b *testing.B) { diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go index 22681115cb6..4c64dca393f 100644 --- a/libgo/go/sync/waitgroup.go +++ b/libgo/go/sync/waitgroup.go @@ -67,11 +67,13 @@ func (wg *WaitGroup) Add(delta int) { return } wg.m.Lock() - for i := int32(0); i < wg.waiters; i++ { - runtime_Semrelease(wg.sema) + if atomic.LoadInt32(&wg.counter) == 0 { + for i := int32(0); i < wg.waiters; i++ { + runtime_Semrelease(wg.sema) + } + wg.waiters = 0 + wg.sema = nil } - wg.waiters = 0 - wg.sema = nil wg.m.Unlock() } diff --git a/libgo/go/sync/waitgroup_test.go b/libgo/go/sync/waitgroup_test.go index 84c4cfc37a3..4c0a043c01e 100644 --- a/libgo/go/sync/waitgroup_test.go +++ b/libgo/go/sync/waitgroup_test.go @@ -5,7 +5,6 @@ package sync_test import ( - "runtime" . "sync" "sync/atomic" "testing" @@ -61,60 +60,60 @@ func TestWaitGroupMisuse(t *testing.T) { t.Fatal("Should panic") } +func TestWaitGroupRace(t *testing.T) { + // Run this test for about 1ms. + for i := 0; i < 1000; i++ { + wg := &WaitGroup{} + n := new(int32) + // spawn goroutine 1 + wg.Add(1) + go func() { + atomic.AddInt32(n, 1) + wg.Done() + }() + // spawn goroutine 2 + wg.Add(1) + go func() { + atomic.AddInt32(n, 1) + wg.Done() + }() + // Wait for goroutine 1 and 2 + wg.Wait() + if atomic.LoadInt32(n) != 2 { + t.Fatal("Spurious wakeup from Wait") + } + } +} + func BenchmarkWaitGroupUncontended(b *testing.B) { type PaddedWaitGroup struct { WaitGroup pad [128]uint8 } - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) - for p := 0; p < procs; p++ { - go func() { - var wg PaddedWaitGroup - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - wg.Add(1) - wg.Done() - wg.Wait() - } - } - c <- true - }() - } - for p := 0; p < procs; p++ { - <-c - } + b.RunParallel(func(pb *testing.PB) { + var wg PaddedWaitGroup + for pb.Next() { + wg.Add(1) + wg.Done() + wg.Wait() + } + }) } func benchmarkWaitGroupAddDone(b *testing.B, localWork int) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) var wg WaitGroup - for p := 0; p < procs; p++ { - go func() { - foo := 0 - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - wg.Add(1) - for i := 0; i < localWork; i++ { - foo *= 2 - foo /= 2 - } - wg.Done() - } + b.RunParallel(func(pb *testing.PB) { + foo := 0 + for pb.Next() { + wg.Add(1) + for i := 0; i < localWork; i++ { + foo *= 2 + foo /= 2 } - c <- foo == 42 - }() - } - for p := 0; p < procs; p++ { - <-c - } + wg.Done() + } + _ = foo + }) } func BenchmarkWaitGroupAddDone(b *testing.B) { @@ -126,34 +125,18 @@ func BenchmarkWaitGroupAddDoneWork(b *testing.B) { } func benchmarkWaitGroupWait(b *testing.B, localWork int) { - const CallsPerSched = 1000 - procs := runtime.GOMAXPROCS(-1) - N := int32(b.N / CallsPerSched) - c := make(chan bool, procs) var wg WaitGroup - wg.Add(procs) - for p := 0; p < procs; p++ { - go wg.Done() - } - for p := 0; p < procs; p++ { - go func() { - foo := 0 - for atomic.AddInt32(&N, -1) >= 0 { - runtime.Gosched() - for g := 0; g < CallsPerSched; g++ { - wg.Wait() - for i := 0; i < localWork; i++ { - foo *= 2 - foo /= 2 - } - } + b.RunParallel(func(pb *testing.PB) { + foo := 0 + for pb.Next() { + wg.Wait() + for i := 0; i < localWork; i++ { + foo *= 2 + foo /= 2 } - c <- foo == 42 - }() - } - for p := 0; p < procs; p++ { - <-c - } + } + _ = foo + }) } func BenchmarkWaitGroupWait(b *testing.B) { diff --git a/libgo/go/syscall/consistency_unix_test.go b/libgo/go/syscall/consistency_unix_test.go deleted file mode 100644 index 6c9fb823560..00000000000 --- a/libgo/go/syscall/consistency_unix_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 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 freebsd dragonfly darwin linux netbsd openbsd - -// This file tests that some basic syscalls are consistent across -// all Unixes. - -package syscall_test - -import "syscall" - -// {Set,Get}priority and needed constants for them -func _() { - var ( - _ func(int, int, int) error = syscall.Setpriority - _ func(int, int) (int, error) = syscall.Getpriority - ) - const ( - _ int = syscall.PRIO_USER - _ int = syscall.PRIO_PROCESS - _ int = syscall.PRIO_PGRP - ) -} - -// termios functions and constants -func _() { - const ( - _ int = syscall.TCIFLUSH - _ int = syscall.TCIOFLUSH - _ int = syscall.TCOFLUSH - ) -} - -func _() { - _ = syscall.Flock_t{ - Type: int16(0), - Whence: int16(0), - Start: int64(0), - Len: int64(0), - Pid: int32(0), - } -} diff --git a/libgo/go/syscall/dir_plan9.go b/libgo/go/syscall/dir_plan9.go index d9fb26b133f..697bf5499c3 100644 --- a/libgo/go/syscall/dir_plan9.go +++ b/libgo/go/syscall/dir_plan9.go @@ -54,7 +54,7 @@ var nullDir = Dir{ } // Null assigns special "don't touch" values to members of d to -// avoid modifiying them during syscall.Wstat. +// avoid modifying them during syscall.Wstat. func (d *Dir) Null() { *d = nullDir } // Marshal encodes a 9P stat message corresponding to d into b diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go index f64202ed110..7f39958437c 100644 --- a/libgo/go/syscall/env_unix.go +++ b/libgo/go/syscall/env_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris // Unix environment variables. diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go index 0cfedb71cf6..6bf28cc8ac2 100644 --- a/libgo/go/syscall/exec_unix.go +++ b/libgo/go/syscall/exec_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux netbsd openbsd solaris // Fork, exec, wait, etc. @@ -194,7 +194,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) return 0, err } - if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) { + if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) { argvp[0] = argv0p } diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go index 85f38e08665..d3580a1bc0c 100644 --- a/libgo/go/syscall/libcall_posix.go +++ b/libgo/go/syscall/libcall_posix.go @@ -244,9 +244,6 @@ func FDZero(set *FdSet) { //sys Getpriority(which int, who int) (prio int, err error) //getpriority(which _C_int, who _C_int) _C_int -//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) -//getrlimit(resource _C_int, rlim *Rlimit) _C_int - //sysnb Getrusage(who int, rusage *Rusage) (err error) //getrusage(who _C_int, rusage *Rusage) _C_int @@ -319,9 +316,6 @@ func Gettimeofday(tv *Timeval) (err error) { //sysnb Setreuid(ruid int, euid int) (err error) //setreuid(ruid Uid_t, euid Uid_t) _C_int -//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) -//setrlimit(resource int, rlim *Rlimit) _C_int - //sysnb Setsid() (pid int, err error) //setsid() Pid_t diff --git a/libgo/go/syscall/libcall_posix_largefile.go b/libgo/go/syscall/libcall_posix_largefile.go index fced6e57dde..c05d3d2a5ec 100644 --- a/libgo/go/syscall/libcall_posix_largefile.go +++ b/libgo/go/syscall/libcall_posix_largefile.go @@ -12,6 +12,9 @@ package syscall //sys Ftruncate(fd int, length int64) (err error) //ftruncate64(fd _C_int, length Offset_t) _C_int +//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) +//getrlimit64(resource _C_int, rlim *Rlimit) _C_int + //sys Lstat(path string, stat *Stat_t) (err error) //lstat64(path *byte, stat *Stat_t) _C_int @@ -30,6 +33,9 @@ package syscall //sys Seek(fd int, offset int64, whence int) (off int64, err error) //lseek64(fd _C_int, offset Offset_t, whence _C_int) Offset_t +//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//setrlimit64(resource int, rlim *Rlimit) _C_int + //sys Stat(path string, stat *Stat_t) (err error) //stat64(path *byte, stat *Stat_t) _C_int diff --git a/libgo/go/syscall/libcall_posix_regfile.go b/libgo/go/syscall/libcall_posix_regfile.go index 6c98e29873c..7de58009393 100644 --- a/libgo/go/syscall/libcall_posix_regfile.go +++ b/libgo/go/syscall/libcall_posix_regfile.go @@ -13,6 +13,9 @@ package syscall //sys Ftruncate(fd int, length int64) (err error) //ftruncate(fd _C_int, length Offset_t) _C_int +//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) +//getrlimit(resource _C_int, rlim *Rlimit) _C_int + //sys Lstat(path string, stat *Stat_t) (err error) //lstat(path *byte, stat *Stat_t) _C_int @@ -31,6 +34,9 @@ package syscall //sys Seek(fd int, offset int64, whence int) (off int64, err error) //lseek(fd _C_int, offset Offset_t, whence _C_int) Offset_t +//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) +//setrlimit(resource int, rlim *Rlimit) _C_int + //sys Stat(path string, stat *Stat_t) (err error) //stat(path *byte, stat *Stat_t) _C_int diff --git a/libgo/go/syscall/mmap_unix_test.go b/libgo/go/syscall/mmap_unix_test.go new file mode 100644 index 00000000000..01f7783022c --- /dev/null +++ b/libgo/go/syscall/mmap_unix_test.go @@ -0,0 +1,22 @@ +// Copyright 2014 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 + +package syscall_test + +import ( + "syscall" + "testing" +) + +func TestMmap(t *testing.T) { + b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE) + if err != nil { + t.Fatalf("Mmap: %v", err) + } + if err := syscall.Munmap(b); err != nil { + t.Fatalf("Munmap: %v", err) + } +} diff --git a/libgo/go/syscall/rlimit_unix_test.go b/libgo/go/syscall/rlimit_unix_test.go deleted file mode 100644 index fc9b02609cf..00000000000 --- a/libgo/go/syscall/rlimit_unix_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2013 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 - -package syscall_test - -import ( - "runtime" - "syscall" - "testing" -) - -func TestRlimit(t *testing.T) { - var rlimit, zero syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) - if err != nil { - t.Fatalf("Getrlimit: save failed: %v", err) - } - if zero == rlimit { - t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) - } - set := rlimit - set.Cur = set.Max - 1 - err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set) - if err != nil { - t.Fatalf("Setrlimit: set failed: %#v %v", set, err) - } - var get syscall.Rlimit - err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get) - if err != nil { - t.Fatalf("Getrlimit: get failed: %v", err) - } - set = rlimit - set.Cur = set.Max - 1 - if set != get { - // Seems like Darwin requires some privilege to - // increase the soft limit of rlimit sandbox, though - // Setrlimit never reports an error. - switch runtime.GOOS { - case "darwin": - default: - t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) - } - } - err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) - if err != nil { - t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) - } -} diff --git a/libgo/go/syscall/route_dragonfly.go b/libgo/go/syscall/route_dragonfly.go index acad7a2be8f..79190d2b01b 100644 --- a/libgo/go/syscall/route_dragonfly.go +++ b/libgo/go/syscall/route_dragonfly.go @@ -30,7 +30,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { } // InterfaceAnnounceMessage represents a routing message containing -// network interface arrival and depature information. +// network interface arrival and departure information. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } diff --git a/libgo/go/syscall/route_freebsd.go b/libgo/go/syscall/route_freebsd.go index d8f80316b8c..15897b1aca9 100644 --- a/libgo/go/syscall/route_freebsd.go +++ b/libgo/go/syscall/route_freebsd.go @@ -8,14 +8,20 @@ package syscall import "unsafe" +// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html. +var freebsdVersion uint32 + +func init() { + freebsdVersion, _ = SysctlUint32("kern.osreldate") +} + func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { switch any.Type { case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE: p := (*RouteMessage)(unsafe.Pointer(any)) return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]} case RTM_IFINFO: - p := (*InterfaceMessage)(unsafe.Pointer(any)) - return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]} + return any.parseInterfaceMessage(b) case RTM_IFANNOUNCE: p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any)) return &InterfaceAnnounceMessage{Header: p.Header} @@ -30,7 +36,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { } // InterfaceAnnounceMessage represents a routing message containing -// network interface arrival and depature information. +// network interface arrival and departure information. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } diff --git a/libgo/go/syscall/route_freebsd_32bit.go b/libgo/go/syscall/route_freebsd_32bit.go new file mode 100644 index 00000000000..93efdddb3bb --- /dev/null +++ b/libgo/go/syscall/route_freebsd_32bit.go @@ -0,0 +1,24 @@ +// Copyright 2014 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 freebsd,386 freebsd,arm + +package syscall + +import "unsafe" + +func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage { + p := (*InterfaceMessage)(unsafe.Pointer(any)) + // FreeBSD 10 and beyond have a restructured mbuf + // packet header view. + // See http://svnweb.freebsd.org/base?view=revision&revision=254804. + if freebsdVersion >= 1000000 { + m := (*ifMsghdr)(unsafe.Pointer(any)) + p.Header.Data.Hwassist = uint32(m.Data.Hwassist) + p.Header.Data.Epoch = m.Data.Epoch + p.Header.Data.Lastchange = m.Data.Lastchange + return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]} + } + return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]} +} diff --git a/libgo/go/syscall/route_freebsd_64bit.go b/libgo/go/syscall/route_freebsd_64bit.go new file mode 100644 index 00000000000..9377f2fedca --- /dev/null +++ b/libgo/go/syscall/route_freebsd_64bit.go @@ -0,0 +1,14 @@ +// Copyright 2014 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 freebsd,amd64 + +package syscall + +import "unsafe" + +func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage { + p := (*InterfaceMessage)(unsafe.Pointer(any)) + return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]} +} diff --git a/libgo/go/syscall/route_netbsd.go b/libgo/go/syscall/route_netbsd.go index a6baa02f802..9883aebaf5f 100644 --- a/libgo/go/syscall/route_netbsd.go +++ b/libgo/go/syscall/route_netbsd.go @@ -27,7 +27,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { } // InterfaceAnnounceMessage represents a routing message containing -// network interface arrival and depature information. +// network interface arrival and departure information. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } diff --git a/libgo/go/syscall/route_openbsd.go b/libgo/go/syscall/route_openbsd.go index 223c1577916..19f902db74b 100644 --- a/libgo/go/syscall/route_openbsd.go +++ b/libgo/go/syscall/route_openbsd.go @@ -27,7 +27,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { } // InterfaceAnnounceMessage represents a routing message containing -// network interface arrival and depature information. +// network interface arrival and departure information. type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go index 5bc4c2acfbd..34c707d9327 100644 --- a/libgo/go/syscall/sockcmsg_unix.go +++ b/libgo/go/syscall/sockcmsg_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux netbsd openbsd solaris // Socket control messages @@ -16,9 +16,9 @@ import ( // Round the length of a raw sockaddr up to align it properly. func cmsgAlignOf(salen int) int { salign := int(sizeofPtr) - // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit - // aligned access to BSD subsystem. - if darwin64Bit { + // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels + // still require 32-bit aligned access to network subsystem. + if darwin64Bit || dragonfly64Bit { salign = 4 } // NOTE: Solaris always uses 32-bit alignment, diff --git a/libgo/go/syscall/socket.go b/libgo/go/syscall/socket.go index 491f52c100e..d96a717303b 100644 --- a/libgo/go/syscall/socket.go +++ b/libgo/go/syscall/socket.go @@ -359,13 +359,18 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from } func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) { + _, err = SendmsgN(fd, p, oob, to, flags) + return +} + +func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) { var ptr *RawSockaddrAny var salen Socklen_t if to != nil { var err error ptr, salen, err = to.sockaddr() if err != nil { - return err + return 0, err } } var msg Msghdr @@ -388,10 +393,13 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) { } msg.Iov = &iov msg.Iovlen = 1 - if err = sendmsg(fd, &msg, flags); err != nil { - return + if n, err = sendmsg(fd, &msg, flags); err != nil { + return 0, err } - return + if len(oob) > 0 && len(p) == 0 { + n = 0 + } + return n, nil } //sys Listen(fd int, n int) (err error) diff --git a/libgo/go/syscall/socket_posix.go b/libgo/go/syscall/socket_posix.go index fd96524f13b..fda7dc65e41 100644 --- a/libgo/go/syscall/socket_posix.go +++ b/libgo/go/syscall/socket_posix.go @@ -27,5 +27,5 @@ package syscall //sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) //recvmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t -//sys sendmsg(s int, msg *Msghdr, flags int) (err error) +//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //sendmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t diff --git a/libgo/go/syscall/socket_xnet.go b/libgo/go/syscall/socket_xnet.go index 04400107d06..3c5b6b41807 100644 --- a/libgo/go/syscall/socket_xnet.go +++ b/libgo/go/syscall/socket_xnet.go @@ -28,5 +28,5 @@ package syscall //sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) //__xnet_recvmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t -//sys sendmsg(s int, msg *Msghdr, flags int) (err error) +//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //__xnet_sendmsg(s _C_int, msg *Msghdr, flags _C_int) Ssize_t diff --git a/libgo/go/syscall/syscall_linux_386.go b/libgo/go/syscall/syscall_linux_386.go index 08422def375..591d3e1a33f 100644 --- a/libgo/go/syscall/syscall_linux_386.go +++ b/libgo/go/syscall/syscall_linux_386.go @@ -4,6 +4,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP) +// so that go vet can check that they are correct. + package syscall import "unsafe" diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go index fcb90dbfa75..a64b05fb5cc 100644 --- a/libgo/go/syscall/syscall_unix.go +++ b/libgo/go/syscall/syscall_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package syscall @@ -25,8 +25,9 @@ func c_syscall32(trap int32, a1, a2, a3, a4, a5, a6 int32) int32 func c_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64 const ( - darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8 - netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4 + darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8 + dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8 + netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4 ) // Do a system call. We look at the size of uintptr to see how to pass diff --git a/libgo/go/syscall/passfd_test.go b/libgo/go/syscall/syscall_unix_test.go index e8ac32d3f57..897ad18a974 100644 --- a/libgo/go/syscall/passfd_test.go +++ b/libgo/go/syscall/syscall_unix_test.go @@ -1,8 +1,8 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2013 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 linux dragonfly darwin freebsd netbsd openbsd +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package syscall_test @@ -13,12 +13,70 @@ import ( "net" "os" "os/exec" + "path/filepath" "runtime" "syscall" "testing" "time" ) +// Tests that below functions, structures and constants are consistent +// on all Unix-like systems. +func _() { + // program scheduling priority functions and constants + var ( + _ func(int, int, int) error = syscall.Setpriority + _ func(int, int) (int, error) = syscall.Getpriority + ) + const ( + _ int = syscall.PRIO_USER + _ int = syscall.PRIO_PROCESS + _ int = syscall.PRIO_PGRP + ) + + // termios constants + const ( + _ int = syscall.TCIFLUSH + _ int = syscall.TCIOFLUSH + _ int = syscall.TCOFLUSH + ) + + // fcntl file locking structure and constants + var ( + _ = syscall.Flock_t{ + Type: int16(0), + Whence: int16(0), + Start: int64(0), + Len: int64(0), + Pid: int32(0), + } + ) + const ( + _ = syscall.F_GETLK + _ = syscall.F_SETLK + _ = syscall.F_SETLKW + ) +} + +// TestFcntlFlock tests whether the file locking structure matches +// the calling convention of each kernel. +func TestFcntlFlock(t *testing.T) { + name := filepath.Join(os.TempDir(), "TestFcntlFlock") + fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0) + if err != nil { + t.Fatalf("Open failed: %v", err) + } + defer syscall.Unlink(name) + defer syscall.Close(fd) + flock := syscall.Flock_t{ + Type: syscall.F_RDLCK, + Start: 0, Len: 0, Whence: 1, + } + if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil { + t.Fatalf("FcntlFlock failed: %v", err) + } +} + // TestPassFD tests passing a file descriptor over a Unix socket. // // This test involved both a parent and child process. The parent @@ -27,9 +85,13 @@ import ( // "-test.run=^TestPassFD$" and an environment variable used to signal // that the test should become the child process instead. func TestPassFD(t *testing.T) { - if runtime.GOOS == "dragonfly" { + switch runtime.GOOS { + case "dragonfly": // TODO(jsing): Figure out why sendmsg is returning EINVAL. - t.Skip("Skipping test on dragonfly") + t.Skip("skipping test on dragonfly") + case "solaris": + // TODO(aram): Figure out why ReadMsgUnix is returning empty message. + t.Skip("skipping test on solaris, see issue 7402") } if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { passFDChild() @@ -204,3 +266,53 @@ func TestUnixRightsRoundtrip(t *testing.T) { } } } + +func TestRlimit(t *testing.T) { + var rlimit, zero syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) + if err != nil { + t.Fatalf("Getrlimit: save failed: %v", err) + } + if zero == rlimit { + t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) + } + set := rlimit + set.Cur = set.Max - 1 + err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set) + if err != nil { + t.Fatalf("Setrlimit: set failed: %#v %v", set, err) + } + var get syscall.Rlimit + err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get) + if err != nil { + t.Fatalf("Getrlimit: get failed: %v", err) + } + set = rlimit + set.Cur = set.Max - 1 + if set != get { + // Seems like Darwin requires some privilege to + // increase the soft limit of rlimit sandbox, though + // Setrlimit never reports an error. + switch runtime.GOOS { + case "darwin": + default: + t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) + } + } + err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) + if err != nil { + t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) + } +} + +func TestSeekFailure(t *testing.T) { + _, err := syscall.Seek(-1, 0, 0) + if err == nil { + t.Fatalf("Seek(-1, 0, 0) did not fail") + } + str := err.Error() // used to crash on Linux + t.Logf("Seek: %v", str) + if str == "" { + t.Fatalf("Seek(-1, 0, 0) return error with empty message") + } +} diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go index e6f3c6d7903..1fbf5c8615f 100644 --- a/libgo/go/testing/benchmark.go +++ b/libgo/go/testing/benchmark.go @@ -417,6 +417,9 @@ func (b *B) RunParallel(body func(*PB)) { }() } wg.Wait() + if n <= uint64(b.N) && !b.Failed() { + b.Fatal("RunParallel: body exited without pb.Next() == false") + } } // SetParallelism sets the number of goroutines used by RunParallel to p*GOMAXPROCS. diff --git a/libgo/go/testing/benchmark_test.go b/libgo/go/testing/benchmark_test.go index 9997b992042..f7ea64e7f1c 100644 --- a/libgo/go/testing/benchmark_test.go +++ b/libgo/go/testing/benchmark_test.go @@ -88,7 +88,6 @@ func TestRunParallelFail(t *testing.T) { // w/o crashing/deadlocking the whole benchmark. b.Log("log") b.Error("error") - b.Fatal("fatal") }) }) } diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index 855f3a9bbe9..8078ba7cc03 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -8,9 +8,17 @@ // func TestXxx(*testing.T) // where Xxx can be any alphanumeric string (but the first letter must not be in // [a-z]) and serves to identify the test routine. -// These TestXxx routines should be declared within the package they are testing. // -// Tests and benchmarks may be skipped if not applicable like this: +// Within these functions, use the Error, Fail or related methods to signal failure. +// +// To write a new test suite, create a file whose name ends _test.go that +// contains the TestXxx functions as described here. Put the file in the same +// package as the one being tested. The file will be excluded from regular +// package builds but will be included when the ``go test'' command is run. +// For more detail, run ``go help test'' and ``go help testflag''. +// +// Tests and benchmarks may be skipped if not applicable with a call to +// the Skip method of *T and *B: // func TestTimeConsuming(t *testing.T) { // if testing.Short() { // t.Skip("skipping test in short mode.") @@ -429,6 +437,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, stopAlarm() if !testOk || !exampleOk { fmt.Println("FAIL") + after() os.Exit(1) } fmt.Println("PASS") diff --git a/libgo/go/text/scanner/scanner.go b/libgo/go/text/scanner/scanner.go index e0d86e343da..db7ca73c68d 100644 --- a/libgo/go/text/scanner/scanner.go +++ b/libgo/go/text/scanner/scanner.go @@ -240,6 +240,9 @@ func (s *Scanner) next() rune { s.srcEnd = i + n s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel if err != nil { + if err != io.EOF { + s.error(err.Error()) + } if s.srcEnd == 0 { if s.lastCharLen > 0 { // previous character was not EOF @@ -248,9 +251,6 @@ func (s *Scanner) next() rune { s.lastCharLen = 0 return EOF } - if err != io.EOF { - s.error(err.Error()) - } // If err == EOF, we won't be getting more // bytes; break to avoid infinite loop. If // err is something else, we don't know if diff --git a/libgo/go/text/scanner/scanner_test.go b/libgo/go/text/scanner/scanner_test.go index 086ab5660eb..7d3f597eb9a 100644 --- a/libgo/go/text/scanner/scanner_test.go +++ b/libgo/go/text/scanner/scanner_test.go @@ -462,6 +462,33 @@ func TestError(t *testing.T) { testError(t, `/*/`, "1:4", "comment not terminated", EOF) } +// An errReader returns (0, err) where err is not io.EOF. +type errReader struct{} + +func (errReader) Read(b []byte) (int, error) { + return 0, io.ErrNoProgress // some error that is not io.EOF +} + +func TestIOError(t *testing.T) { + s := new(Scanner).Init(errReader{}) + errorCalled := false + s.Error = func(s *Scanner, msg string) { + if !errorCalled { + if want := io.ErrNoProgress.Error(); msg != want { + t.Errorf("msg = %q, want %q", msg, want) + } + errorCalled = true + } + } + tok := s.Scan() + if tok != EOF { + t.Errorf("tok = %s, want EOF", TokenString(tok)) + } + if !errorCalled { + t.Errorf("error handler not called") + } +} + func checkPos(t *testing.T, got, want Position) { if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column { t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d", diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go index f622ac7dcee..7c6efd59cde 100644 --- a/libgo/go/text/template/doc.go +++ b/libgo/go/text/template/doc.go @@ -20,7 +20,7 @@ The input text for a template is UTF-8-encoded text in any format. "{{" and "}}"; all text outside actions is copied to the output unchanged. Actions may not span newlines, although comments can. -Once constructed, a template may be executed safely in parallel. +Once parsed, a template may be executed safely in parallel. Here is a trivial example that prints "17 items are made of wool". diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go index 6de37a19963..2f323126453 100644 --- a/libgo/go/text/template/exec.go +++ b/libgo/go/text/template/exec.go @@ -108,6 +108,10 @@ func errRecover(errp *error) { // ExecuteTemplate applies the template associated with t that has the given name // to the specified data object and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel. func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { tmpl := t.tmpl[name] if tmpl == nil { @@ -118,6 +122,10 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) // Execute applies a parsed template to the specified data object, // and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel. func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { defer errRecover(&err) value := reflect.ValueOf(data) diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index 6f92c126268..9f210ea27df 100644 --- a/libgo/go/time/format.go +++ b/libgo/go/time/format.go @@ -102,7 +102,7 @@ const ( // std0x records the std values for "01", "02", ..., "06". var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear} -// startsWithLowerCase reports whether the the string has a lower-case letter at the beginning. +// startsWithLowerCase reports whether the string has a lower-case letter at the beginning. // Its purpose is to prevent matching strings like "Month" when looking for "Mon". func startsWithLowerCase(str string) bool { if len(str) == 0 { @@ -1037,8 +1037,8 @@ func parseTimeZone(value string) (length int, ok bool) { if len(value) < 3 { return 0, false } - // Special case 1: This is the only zone with a lower-case letter. - if len(value) >= 4 && value[:4] == "ChST" { + // Special case 1: ChST and MeST are the only zones with a lower-case letter. + if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") { return 4, true } // Special case 2: GMT may have an hour offset; treat it specially. @@ -1240,5 +1240,8 @@ func ParseDuration(s string) (Duration, error) { if neg { f = -f } + if f < float64(-1<<63) || f > float64(1<<63-1) { + return 0, errors.New("time: overflow parsing duration") + } return Duration(f), nil } diff --git a/libgo/go/time/format_test.go b/libgo/go/time/format_test.go index 93273392e96..70e653e6706 100644 --- a/libgo/go/time/format_test.go +++ b/libgo/go/time/format_test.go @@ -333,6 +333,7 @@ var parseTimeZoneTests = []ParseTimeZoneTest{ {"GMT-5 hi there", 5, true}, {"GMT-51 hi there", 3, true}, {"ChST hi there", 4, true}, + {"MeST hi there", 4, true}, {"MSDx", 3, true}, {"MSDY", 0, false}, // four letters must end in T. {"ESAST hi", 5, true}, diff --git a/libgo/go/time/internal_test.go b/libgo/go/time/internal_test.go index 4ba6d478deb..2243d3668de 100644 --- a/libgo/go/time/internal_test.go +++ b/libgo/go/time/internal_test.go @@ -29,7 +29,7 @@ func CheckRuntimeTimerOverflow() error { // detection logic in NewTimer: we're testing the underlying // runtime.addtimer function. r := &runtimeTimer{ - when: nano() + (1<<63 - 1), + when: runtimeNano() + (1<<63 - 1), f: empty, arg: nil, } diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go index 4f55bebe62a..6a03f417bd0 100644 --- a/libgo/go/time/sleep.go +++ b/libgo/go/time/sleep.go @@ -8,10 +8,8 @@ package time // A negative or zero duration causes Sleep to return immediately. func Sleep(d Duration) -func nano() int64 { - sec, nsec := now() - return sec*1e9 + int64(nsec) -} +// runtimeNano returns the current value of the runtime clock in nanoseconds. +func runtimeNano() int64 // Interface to timers implemented in package runtime. // Must be in sync with ../runtime/runtime.h:/^struct.Timer$ @@ -29,9 +27,9 @@ type runtimeTimer struct { // zero because of an overflow, MaxInt64 is returned. func when(d Duration) int64 { if d <= 0 { - return nano() + return runtimeNano() } - t := nano() + int64(d) + t := runtimeNano() + int64(d) if t < 0 { t = 1<<63 - 1 // math.MaxInt64 } @@ -92,7 +90,7 @@ func sendTime(now int64, c interface{}) { // the desired behavior when the reader gets behind, // because the sends are periodic. select { - case c.(chan Time) <- Unix(0, now): + case c.(chan Time) <- Now(): default: } } diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go index e86e294ee7a..7c2dcaf5471 100644 --- a/libgo/go/time/sleep_test.go +++ b/libgo/go/time/sleep_test.go @@ -74,26 +74,13 @@ func benchmark(b *testing.B, bench func(n int)) { for i := 0; i < len(garbage); i++ { garbage[i] = AfterFunc(Hour, nil) } - - const batch = 1000 - P := runtime.GOMAXPROCS(-1) - N := int32(b.N / batch) - b.ResetTimer() - var wg sync.WaitGroup - wg.Add(P) - - for p := 0; p < P; p++ { - go func() { - for atomic.AddInt32(&N, -1) >= 0 { - bench(batch) - } - wg.Done() - }() - } - - wg.Wait() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + bench(1000) + } + }) b.StopTimer() for i := 0; i < len(garbage); i++ { @@ -361,19 +348,18 @@ func TestReset(t *testing.T) { // Test that sleeping for an interval so large it overflows does not // result in a short sleep duration. func TestOverflowSleep(t *testing.T) { - const timeout = 25 * Millisecond const big = Duration(int64(1<<63 - 1)) select { case <-After(big): t.Fatalf("big timeout fired") - case <-After(timeout): + case <-After(25 * Millisecond): // OK } const neg = Duration(-1 << 63) select { case <-After(neg): // OK - case <-After(timeout): + case <-After(1 * Second): t.Fatalf("negative timeout didn't fire") } } diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go index 36c214b6b09..379e13d6a53 100644 --- a/libgo/go/time/sys_unix.go +++ b/libgo/go/time/sys_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package time diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go index b92c339c02a..19007841e1a 100644 --- a/libgo/go/time/tick.go +++ b/libgo/go/time/tick.go @@ -17,6 +17,7 @@ type Ticker struct { // time with a period specified by the duration argument. // It adjusts the intervals or drops ticks to make up for slow receivers. // The duration d must be greater than zero; if not, NewTicker will panic. +// Stop the ticker to release associated resources. func NewTicker(d Duration) *Ticker { if d <= 0 { panic(errors.New("non-positive interval for NewTicker")) @@ -28,7 +29,7 @@ func NewTicker(d Duration) *Ticker { t := &Ticker{ C: c, r: runtimeTimer{ - when: nano() + int64(d), + when: when(d), period: int64(d), f: sendTime, arg: c, diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go index c504df74013..0a2b0914283 100644 --- a/libgo/go/time/time.go +++ b/libgo/go/time/time.go @@ -934,6 +934,8 @@ func (t *Time) GobDecode(data []byte) error { // The time is a quoted string in RFC 3339 format, with sub-second precision added if present. func (t Time) MarshalJSON() ([]byte, error) { if y := t.Year(); y < 0 || y >= 10000 { + // RFC 3339 is clear that years are 4 digits exactly. + // See golang.org/issue/4556#c15 for more discussion. return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]") } return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go index 2615517d9ad..4ae7da5a443 100644 --- a/libgo/go/time/time_test.go +++ b/libgo/go/time/time_test.go @@ -842,6 +842,7 @@ var parseDurationTests = []struct { {"-.", false, 0}, {".s", false, 0}, {"+.s", false, 0}, + {"3000000h", false, 0}, // overflow } func TestParseDuration(t *testing.T) { diff --git a/libgo/go/time/zoneinfo_read.go b/libgo/go/time/zoneinfo_read.go index 4bb4bf665cc..de9ebb41c82 100644 --- a/libgo/go/time/zoneinfo_read.go +++ b/libgo/go/time/zoneinfo_read.go @@ -68,7 +68,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) { // 1-byte version, then 15 bytes of padding var p []byte - if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' { + if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' && p[0] != '3' { return nil, badData } @@ -123,7 +123,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) { return nil, badData } - // If version == 2, the entire file repeats, this time using + // If version == 2 or 3, the entire file repeats, this time using // 8-byte ints for txtimes and leap seconds. // We won't need those until 2106. diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go index 03f54a69360..ede5330f5cc 100644 --- a/libgo/go/time/zoneinfo_test.go +++ b/libgo/go/time/zoneinfo_test.go @@ -9,6 +9,16 @@ import ( "time" ) +func TestVersion3(t *testing.T) { + t.Skip("gccgo does not use the zip file") + time.ForceZipFileForTesting(true) + defer time.ForceZipFileForTesting(false) + _, err := time.LoadLocation("Asia/Jerusalem") + if err != nil { + t.Fatal(err) + } +} + // Test that we get the correct results for times before the first // transition time. To do this we explicitly check early dates in a // couple of specific timezones. diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go index e70decb36cb..3fe8e55795c 100644 --- a/libgo/go/time/zoneinfo_unix.go +++ b/libgo/go/time/zoneinfo_unix.go @@ -2,7 +2,7 @@ // 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 +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris // Parse "zoneinfo" time zone file. // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others. diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go index 377a8921538..6046743e67d 100644 --- a/libgo/go/time/zoneinfo_windows.go +++ b/libgo/go/time/zoneinfo_windows.go @@ -90,7 +90,7 @@ func toEnglishName(stdname, dstname string) (string, error) { return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`) } -// extractCAPS exracts capital letters from description desc. +// extractCAPS extracts capital letters from description desc. func extractCAPS(desc string) string { var short []rune for _, c := range desc { diff --git a/libgo/go/unicode/letter.go b/libgo/go/unicode/letter.go index 3b389e93f14..977bd2b3b05 100644 --- a/libgo/go/unicode/letter.go +++ b/libgo/go/unicode/letter.go @@ -316,7 +316,7 @@ type foldPair struct { // SimpleFold iterates over Unicode code points equivalent under // the Unicode-defined simple case folding. Among the code points // equivalent to rune (including rune itself), SimpleFold returns the -// smallest rune >= r if one exists, or else the smallest rune >= 0. +// smallest rune > r if one exists, or else the smallest rune >= 0. // // For example: // SimpleFold('A') = 'a' diff --git a/libgo/go/unicode/letter_test.go b/libgo/go/unicode/letter_test.go index e4d5572a0fe..4ee11fb364f 100644 --- a/libgo/go/unicode/letter_test.go +++ b/libgo/go/unicode/letter_test.go @@ -387,32 +387,20 @@ func TestTurkishCase(t *testing.T) { } var simpleFoldTests = []string{ - // SimpleFold could order its returned slices in any order it wants, - // but we know it orders them in increasing order starting at in - // and looping around from MaxRune to 0. + // SimpleFold(x) returns the next equivalent rune > x or wraps + // around to smaller values. // Easy cases. "Aa", - "aA", "δΔ", - "Δδ", // ASCII special cases. "KkK", - "kKK", - "KKk", "Ssſ", - "sſS", - "ſSs", // Non-ASCII special cases. "ρϱΡ", - "ϱΡρ", - "Ρρϱ", "ͅΙιι", - "Ιιιͅ", - "ιιͅΙ", - "ιͅΙι", // Extra special cases: has lower/upper but no case fold. "İ", diff --git a/libgo/go/unicode/utf16/utf16.go b/libgo/go/unicode/utf16/utf16.go index 903e4012aa4..c0e47c535ab 100644 --- a/libgo/go/unicode/utf16/utf16.go +++ b/libgo/go/unicode/utf16/utf16.go @@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool { // the Unicode replacement code point U+FFFD. func DecodeRune(r1, r2 rune) rune { if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 { - return (rune(r1)-surr1)<<10 | (rune(r2) - surr2) + 0x10000 + return (r1-surr1)<<10 | (r2 - surr2) + 0x10000 } return replacementChar } diff --git a/libgo/go/unicode/utf8/utf8.go b/libgo/go/unicode/utf8/utf8.go index 93d0be5e0c1..0dc859a041b 100644 --- a/libgo/go/unicode/utf8/utf8.go +++ b/libgo/go/unicode/utf8/utf8.go @@ -329,37 +329,29 @@ func RuneLen(r rune) int { // It returns the number of bytes written. func EncodeRune(p []byte, r rune) int { // Negative values are erroneous. Making it unsigned addresses the problem. - if uint32(r) <= rune1Max { + switch i := uint32(r); { + case i <= rune1Max: p[0] = byte(r) return 1 - } - - if uint32(r) <= rune2Max { + case i <= rune2Max: p[0] = t2 | byte(r>>6) p[1] = tx | byte(r)&maskx return 2 - } - - if uint32(r) > MaxRune { + case i > MaxRune, surrogateMin <= i && i <= surrogateMax: r = RuneError - } - - if surrogateMin <= r && r <= surrogateMax { - r = RuneError - } - - if uint32(r) <= rune3Max { + fallthrough + case i <= rune3Max: p[0] = t3 | byte(r>>12) p[1] = tx | byte(r>>6)&maskx p[2] = tx | byte(r)&maskx return 3 + default: + p[0] = t4 | byte(r>>18) + p[1] = tx | byte(r>>12)&maskx + p[2] = tx | byte(r>>6)&maskx + p[3] = tx | byte(r)&maskx + return 4 } - - p[0] = t4 | byte(r>>18) - p[1] = tx | byte(r>>12)&maskx - p[2] = tx | byte(r>>6)&maskx - p[3] = tx | byte(r)&maskx - return 4 } // RuneCount returns the number of runes in p. Erroneous and short |